Максимальное целое число Ruby


87

Мне нужно уметь определять максимальное целое число системы в Ruby. Кто-нибудь знает, как или возможно ли это?

Ответы:


49

Ruby автоматически преобразует целые числа в большой целочисленный класс, когда они переполняются, поэтому (практически) нет ограничений на их размер.

Если вы ищете размер машины, то есть 64- или 32-битную, я нашел этот трюк на 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

Если вы ищете размер объектов Fixnum (целые числа, достаточно маленькие, чтобы их можно было хранить в одном машинном слове), вы можете позвонить, 0.sizeчтобы получить количество байтов. Думаю, в 32-битных сборках должно быть 4, но сейчас я не могу это проверить. Кроме того, наибольший Fixnum, по-видимому, равен 2**30 - 1(или 2**62 - 1), потому что один бит используется для обозначения его как целого числа вместо ссылки на объект.


1
Совершенно уверен, что вам нужно 2 ** (размер_машины * 8) -1; 2 ** 4-1 = 15, что не очень много.
Cebjyre

Упс, думаю, я начал слишком много думать о байтах, а не о битах.
Мэтью Крамли,

10
ВНИМАНИЕ: код бесполезен. Прочтите правку, игнорируйте код. Для Ruby он не находит ничего максимума. Он находит это для кода, который не использует тегированные указатели.
CJ.

теперь (2018-01-21) это 32 бита даже в 64-битном рубине на Windows (у cygwin правильные 64-
битные

81
FIXNUM_MAX = (2**(0.size * 8 -2) -1)
FIXNUM_MIN = -(2**(0.size * 8 -2))

5
Почему вы вычли 2 бита вместо 1 для знака? Я проверил это, и это кажется правильным, но почему Ruby использует 2 бита для знака?
Матиас

29
@Matthias Дополнительный бит используется для обозначения значения как целого числа (в отличие от указателя на объект).
Мэтью Крамли

2
По крайней мере, это не относится к JRuby. В JRuby Fixnumвсегда 64 бит (а не 63 или 31 бит, как в YARV) независимо от размера машинного слова, и бит тега отсутствует.
Jörg W Mittag

13

Читаете дружелюбное руководство? Кто бы хотел это сделать?

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"

Кажется, это единственный ответ, который возвращает числа при переходе от Fixnum к Bignum, что, на мой взгляд, означает, что это самый большой Fixnum в Ruby.
Железный Человек

11

В Ruby Fixnum автоматически конвертируются в Bignum.

Чтобы найти максимально возможное количество Fixnum, вы можете сделать что-то вроде этого:

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)

Беззастенчиво вырванный из разговора о рубиновых разговорах . Смотрите там подробности.


5
Если вы puts (Fixnum::MAX + 1).classэто сделаете, это не вернется, Bignumкак кажется, как должно. Если поменять 8на 16это будет.
Железный Человек

сейчас это недоступно
allenhwkim

1

Начиная с Ruby 2.4 максимума нет, поскольку Bignum и Fixnum объединились в Integer. см. 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

Переполнения не будет, произойдет нехватка памяти.


0

как отметил @ Jörg W Mittag: в jruby размер фиксированного числа всегда составляет 8 байтов. Этот фрагмент кода показывает правду:

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
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.