Ruby max inteiro

87

Eu preciso ser capaz de determinar um número inteiro máximo do sistema em Ruby. Alguém sabe como, ou se é possível?

Allyn
fonte

Respostas:

49

Ruby converte inteiros automaticamente em uma classe de inteiro grande quando eles estouram, então não há (praticamente) limite para o quão grande eles podem ser.

Se você está procurando o tamanho da máquina, ou seja, 64 ou 32 bits, encontrei este truque em 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

Se você estiver procurando pelo tamanho dos objetos Fixnum (inteiros pequenos o suficiente para armazenar em uma única palavra de máquina), você pode chamar 0.sizepara obter o número de bytes. Eu acho que deveria ser 4 em compilações de 32 bits, mas não posso testar isso agora. Além disso, o maior Fixnum é aparentemente 2**30 - 1(ou 2**62 - 1), porque um bit é usado para marcá-lo como um inteiro em vez de uma referência de objeto.

Matthew Crumley
fonte
1
Certeza de que deseja 2 ** (tamanho_máquina * 8) -1; 2 ** 4-1 = 15 que não é nada muito grande.
Cebjyre
Opa, acho que comecei a pensar muito sobre bytes em vez de bits.
Matthew Crumley
10
AVISO: o código é inútil. Leia a edição, ignore o código. Não encontra o máximo de nada para Ruby. Ele o encontra para código que não usa ponteiros marcados.
CJ.
agora (21/01/2018) são 32 bits, mesmo em ruby ​​de 64 bits no Windows (o cygwin tem 64 bits adequados, por outro lado)
graywolf
81
FIXNUM_MAX = (2**(0.size * 8 -2) -1)
FIXNUM_MIN = -(2**(0.size * 8 -2))

fonte
5
Por que você subtraiu 2 bits em vez de 1 para o sinal? Eu testei isso e parece estar correto, mas por que Ruby usa 2 bits para o sinal?
Matthias
29
@Matthias Um bit extra é usado para marcar o valor como um inteiro (em oposição a um ponteiro para um objeto).
Matthew Crumley,
2
Isso não é verdade para JRuby, pelo menos. Em JRuby, Fixnumé sempre 64 bits (não 63 ou 31 bits como em YARV), independentemente do tamanho da palavra da máquina, e não há bit de tag.
Jörg W Mittag
13

Lendo o manual amigável? Quem iria querer fazer isso?

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
fonte
Esta parece ser a única resposta que retorna números na transição de Fixnum para Bignum, o que, para mim, significa que é o maior Fixnum em Ruby.
o Homem de Lata
11

Em rubi, Fixnums são automaticamente convertidos em Bignums.

Para encontrar o Fixnum mais alto possível, você pode fazer algo assim:

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)

Desavergonhadamente arrancado de uma conversa de rubi . Procure aqui para mais detalhes.

tommym
fonte
5
Se você fizer puts (Fixnum::MAX + 1).classisso, não retornará Bignumcomo deveria. Se você mudar 8para 16isso.
The Tin Man
isto não está disponível agora
allenhwkim
1

Não há máximo desde o Ruby 2.4, já que Bignum e Fixnum foram unificados em Integer. ver Recurso # 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

Não haverá transbordamento, o que aconteceria é uma falta de memória.

Estani
fonte
0

como @ Jörg W Mittag apontou: em jruby, fix num size tem sempre 8 bytes de comprimento. Este snippet de código mostra a verdade:

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
fonte