Entier Ruby max

87

Je dois être en mesure de déterminer un nombre entier maximal de systèmes dans Ruby. Quelqu'un sait comment, ou si c'est possible?

Allyn
la source

Réponses:

49

Ruby convertit automatiquement les entiers en une grande classe d'entiers lorsqu'ils débordent, il n'y a donc (pratiquement) aucune limite à leur taille.

Si vous recherchez la taille de la machine, c'est-à-dire 64 ou 32 bits, j'ai trouvé cette astuce sur ruby-forum.com :

machine_bytes = ['foo'].pack('p').size
machine_bits = machine_bytes * 8
machine_max_signed = 2**(machine_bits-1) - 1
machine_max_unsigned = 2**machine_bits - 1

Si vous recherchez la taille des objets Fixnum (nombres entiers suffisamment petits pour être stockés dans un seul mot machine), vous pouvez appeler 0.sizepour obtenir le nombre d'octets. Je suppose que ce devrait être 4 sur les versions 32 bits, mais je ne peux pas le tester pour le moment. En outre, le plus grand Fixnum est apparemment 2**30 - 1(ou 2**62 - 1), car un bit est utilisé pour le marquer comme un entier au lieu d'une référence d'objet.

Matthew Crumley
la source
1
À peu près sûr que vous voulez 2 ** (machine_size * 8) -1; 2 ** 4-1 = 15 ce qui n'est pas un très grand rien.
Cebjyre
Oups, je suppose que j'ai commencé à trop penser aux octets plutôt qu'aux bits.
Matthew Crumley
10
AVERTISSEMENT: le code est inutile. Lisez la modification, ignorez le code. Il ne trouve rien au maximum pour Ruby. Il le trouve pour le code qui n'utilise pas de pointeurs balisés.
CJ.
maintenant (2018-01-21) c'est 32 bits même en rubis 64 bits sur Windows (cygwin a un 64 bits approprié)
graywolf
81
FIXNUM_MAX = (2**(0.size * 8 -2) -1)
FIXNUM_MIN = -(2**(0.size * 8 -2))

la source
5
Pourquoi avez-vous soustrait 2 bits au lieu de 1 pour le signe? J'ai testé cela et cela semble correct, mais pourquoi Ruby utilise-t-il 2 bits pour le signe?
Matthias
29
@Matthias Un bit supplémentaire est utilisé pour marquer la valeur comme un entier (par opposition à un pointeur vers un objet).
Matthew Crumley
2
Ce n'est pas vrai pour JRuby, du moins. Dans JRuby, Fixnumc'est toujours 64 bits (pas 63 ou 31 bits comme dans YARV) quelle que soit la taille du mot machine, et il n'y a pas de bit d'étiquette.
Jörg W Mittag
13

Lire le manuel convivial? Qui voudrait faire ça?

start = Time.now
largest_known_fixnum = 1
smallest_known_bignum = nil

until smallest_known_bignum == largest_known_fixnum + 1
  if smallest_known_bignum.nil?
    next_number_to_try = largest_known_fixnum * 1000
  else
    next_number_to_try = (smallest_known_bignum + largest_known_fixnum) / 2 # Geometric mean would be more efficient, but more risky
  end

  if next_number_to_try <= largest_known_fixnum ||
       smallest_known_bignum && next_number_to_try >= smallest_known_bignum
    raise "Can't happen case" 
  end

  case next_number_to_try
    when Bignum then smallest_known_bignum = next_number_to_try
    when Fixnum then largest_known_fixnum = next_number_to_try
    else raise "Can't happen case"
  end
end

finish = Time.now
puts "The largest fixnum is #{largest_known_fixnum}"
puts "The smallest bignum is #{smallest_known_bignum}"
puts "Calculation took #{finish - start} seconds"
Andrew Grimm
la source
Cela semble être la seule réponse qui renvoie des nombres lors de la transition de Fixnum à Bignum, ce qui, pour moi, signifie que c'est le plus grand Fixnum de Ruby.
The Tin Man
11

Dans ruby, les Fixnums sont automatiquement convertis en Bignums.

Pour trouver le Fixnum le plus élevé possible, vous pouvez faire quelque chose comme ceci:

class Fixnum
 N_BYTES = [42].pack('i').size
 N_BITS = N_BYTES * 8
 MAX = 2 ** (N_BITS - 2) - 1
 MIN = -MAX - 1
end
p(Fixnum::MAX)

Sans vergogne arraché à une discussion rubis . Regardez là pour plus de détails.

tommym
la source
5
Si vous faites puts (Fixnum::MAX + 1).classcela ne revient pas Bignumcomme il semble que ce soit le cas. Si vous changez 8à 16ce sera.
The Tin Man
ce n'est pas disponible maintenant
allenhwkim
1

Il n'y a pas de maximum depuis Ruby 2.4, car Bignum et Fixnum se sont unifiés en Integer. voir Feature # 12005

> (2 << 1000).is_a? Fixnum
(irb):322: warning: constant ::Fixnum is deprecated
=> true

> 1.is_a? Bignum
(irb):314: warning: constant ::Bignum is deprecated
=> true

> (2 << 1000).class
=> Integer

Il n'y aura pas de débordement, ce qui se passerait est un manque de mémoire.

estani
la source
0

comme @ Jörg W Mittag l'a souligné: dans jruby, la taille du numéro fixe est toujours de 8 octets. Cet extrait de code montre la vérité:

fmax = ->{
  if RUBY_PLATFORM == 'java'
    2**63 - 1
  else
    2**(0.size * 8 - 2) - 1
  end
}.call

p fmax.class     # Fixnum

fmax = fmax + 1  

p fmax.class     #Bignum
Hailong Cao
la source