Макс. Ціле число в рубіні


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щоб отримати кількість байтів. Я гадаю, це має бути 4 для 32-розрядних збірок, але я не можу перевірити це зараз. Крім того, найбільшим Fixnum є, мабуть, 2**30 - 1(або 2**62 - 1), оскільки один біт використовується, щоб позначити його як ціле число, а не як посилання на об'єкт.


1
Впевнений, що вам потрібно 2 ** (розмір_машини * 8) -1; 2 ** 4-1 = 15, що не дуже велике.
Cebjyre

На жаль, я думаю, я почав занадто багато думати про байти, а не про біти.
Метью Крамлі

10
ПОПЕРЕДЖЕННЯ: Код марний. Прочитайте редагування, ігноруйте код. Це не знаходить максимум для Рубі. Він знаходить його для коду, який не використовує мічені вказівники.
CJ.

зараз (21.01.2018) це 32 біти, навіть у 64-бітовому рубіні на вікнах (cygwin має належні 64-бітні з іншого боку)
greywolf

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

5
Чому для знаку ви відняли 2 біти замість 1? Я перевірив це, і, здається, це правильно, але чому Рубі використовує 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

У рубінових Fixnums автоматично перетворюються на Bignums.

Щоб знайти найвищий можливий 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. див. функцію # 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.