Muszę być w stanie określić maksymalną liczbę całkowitą systemu w Rubim. Czy ktoś wie jak, czy to możliwe?
Odpowiedzi:
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))
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"
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.
puts (Fixnum::MAX + 1).class
, nie wróci Bignum
tak, jak się wydaje. W przypadku zmiany 8
na 16
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.
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