Número entero máximo de rubí

87

Necesito poder determinar un número entero máximo del sistema en Ruby. ¿Alguien sabe cómo, o si es posible?

Allyn
fuente

Respuestas:

49

Ruby convierte automáticamente los enteros en una clase de entero grande cuando se desbordan, por lo que (prácticamente) no hay límite para su tamaño.

Si está buscando el tamaño de la máquina, es decir, 64 o 32 bits, encontré este truco en 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 está buscando el tamaño de los objetos Fixnum (números enteros lo suficientemente pequeños como para almacenarlos en una sola palabra de máquina), puede llamar 0.sizepara obtener el número de bytes. Supongo que debería ser 4 en compilaciones de 32 bits, pero no puedo probar eso en este momento. Además, el Fixnum más grande es aparentemente 2**30 - 1(o 2**62 - 1), porque se usa un bit para marcarlo como un número entero en lugar de una referencia de objeto.

Matthew Crumley
fuente
1
Seguro que quieres 2 ** (machine_size * 8) -1; 2 ** 4-1 = 15 que no es nada muy grande.
Cebjyre
Vaya, creo que empecé a pensar demasiado en bytes en lugar de bits.
Matthew Crumley
10
ADVERTENCIA: El código es inútil. Lea la edición, ignore el código. No encuentra el máximo de nada para Ruby. Lo encuentra para el código que no usa punteros etiquetados.
CJ.
ahora (2018-01-21) son 32 bits incluso en ruby ​​de 64 bits en Windows (cygwin tiene 64 bits adecuados por otro lado)
graywolf
81
FIXNUM_MAX = (2**(0.size * 8 -2) -1)
FIXNUM_MIN = -(2**(0.size * 8 -2))

fuente
5
¿Por qué restaste 2 bits en lugar de 1 para el signo? Probé esto y parece ser correcto, pero ¿por qué Ruby usa 2 bits para el signo?
Matthias
29
@Matthias Se utiliza un bit adicional para marcar el valor como un número entero (en lugar de un puntero a un objeto).
Matthew Crumley
2
Esto no es cierto para JRuby, al menos. En JRuby, Fixnumsiempre es de 64 bits (no de 63 o 31 bits como en YARV) independientemente del tamaño de la palabra de la máquina, y no hay bit de etiqueta.
Jörg W Mittag
13

¿Leyendo el manual amigable? ¿Quién querría hacer eso?

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
fuente
Esta parece ser la única respuesta que devuelve números en la transición de Fixnum a Bignum, lo que, para mí, significa que es el Fixnum más grande de Ruby.
The Tin Man
11

En ruby, los Fixnums se convierten automáticamente en Bignums.

Para encontrar el Fixnum más alto posible, puede hacer algo como esto:

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)

Desvergonzadamente arrancado de una discusión de rubí . Busque allí más detalles.

tommym
fuente
5
Si lo hace, puts (Fixnum::MAX + 1).classesto no regresa Bignumcomo debería. Si cambia 8a 16lo hará.
The Tin Man
esto no está disponible ahora
allenhwkim
1

No hay un máximo desde Ruby 2.4, ya que Bignum y Fixnum se unificaron en Integer. ver Característica # 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

No habrá ningún desbordamiento, lo que pasaría es una falta de memoria.

estani
fuente
0

como señaló @ Jörg W Mittag: en jruby, el tamaño del número fijo es siempre de 8 bytes de longitud. Este fragmento de código muestra la verdad:

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
fuente