Muszę być w stanie określić maksymalną liczbę całkowitą systemu w Rubim. Czy ktoś wie jak, czy to możliwe?
87
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.size
aby 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.
FIXNUM_MAX = (2**(0.size * 8 -2) -1) FIXNUM_MIN = -(2**(0.size * 8 -2))
źródło
Fixnum
jest zawsze 64-bitowy (nie 63 lub 31-bitowy jak w YARV), niezależnie od rozmiaru słowa maszynowego i nie ma bitu tagu.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"
źródło
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.
źródło
puts (Fixnum::MAX + 1).class
, nie wróciBignum
tak, jak się wydaje. W przypadku zmiany8
na16
nim będzie.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.
źródło
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
źródło