Maksymalna liczba całkowita w języku Ruby


87

Muszę być w stanie określić maksymalną liczbę całkowitą systemu w Rubim. Czy ktoś wie jak, czy to możliwe?

Odpowiedzi:


49

Ruby automatycznie konwertuje liczby całkowite na dużą klasę liczb całkowitych, gdy się przepełnią, więc (praktycznie) nie ma ograniczeń co do tego, jak duże mogą być.

Jeśli szukasz rozmiaru maszyny, czyli 64- lub 32-bitowej, znalazłem tę sztuczkę na 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

Jeśli szukasz rozmiaru obiektów Fixnum (liczby całkowite wystarczająco małe, aby przechowywać je w jednym słowie maszynowym), możesz wywołać, 0.sizeaby uzyskać liczbę bajtów. Wydaje mi się, że powinno to być 4 w wersjach 32-bitowych, ale nie mogę tego teraz przetestować. Najwyraźniej również największy Fixnum to 2**30 - 1(lub 2**62 - 1), ponieważ jeden bit jest używany do oznaczenia go jako liczby całkowitej zamiast odniesienia do obiektu.


1
Na pewno chcesz 2 ** (machine_size * 8) -1; 2 ** 4-1 = 15, co nie jest niczym dużym.
Cebjyre

Ups, chyba za dużo myślałem o bajtach zamiast bitach.
Matthew Crumley,

10
OSTRZEŻENIE: kod jest bezużyteczny. Przeczytaj edycję, zignoruj ​​kod. Nie znajduje niczego maksymalnego dla Rubiego. Znajduje go dla kodu, który nie używa oznaczonych wskaźników.
CJ.

teraz (2018-01-21) to 32 bity nawet w 64-bitowym rubinie na Windowsie (z drugiej strony cygwin ma właściwy 64-bitowy)
graywolf

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

5
Dlaczego odjąłeś 2 bity zamiast 1 dla znaku? Przetestowałem to i wydaje się, że jest poprawne, ale dlaczego Ruby używa 2 bitów do znaku?
Matthias

29
@Matthias Dodatkowy bit służy do oznaczania wartości jako liczby całkowitej (w przeciwieństwie do wskaźnika do obiektu).
Matthew Crumley

2
Nie dotyczy to przynajmniej JRuby. W JRuby Fixnumjest zawsze 64-bitowy (nie 63 lub 31-bitowy jak w YARV), niezależnie od rozmiaru słowa maszynowego i nie ma bitu tagu.
Jörg W Mittag

13

Czytasz przyjazną instrukcję? Kto by chciał to zrobić?

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"

Wydaje się, że jest to jedyna odpowiedź, która zwraca liczby przy przejściu z Fixnum do Bignum, co według mnie oznacza, że ​​jest to największe Fixnum w Rubim.
Tin Man,

11

W ruby ​​Fixnum są automatycznie konwertowane na Bignum.

Aby znaleźć najwyższy możliwy Fixnum, możesz zrobić coś takiego:

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)

Bezwstydnie wyrwany z dyskusji o rubinach . Poszukaj tam więcej szczegółów.


5
Jeśli to zrobisz puts (Fixnum::MAX + 1).class, nie wróci Bignumtak, jak się wydaje. W przypadku zmiany 8na 16nim będzie.
Tin Man,

to nie jest teraz dostępne
allenhwkim

1

Od wersji Ruby 2.4 nie ma maksimum, ponieważ Bignum i Fixnum zostały ujednolicone w Integer. patrz funkcja nr 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

Nie będzie przepełnienia, co by się stało, to brak pamięci.


0

jak zauważył @ Jörg W Mittag: w jruby rozmiar fix num ma zawsze długość 8 bajtów. Ten fragment kodu pokazuje prawdę:

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
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.