2009-02-11 10 views

Odpowiedz

42

Ruby automatycznie konwertuje liczby całkowite do dużej klasy całkowitej kiedy przelewem, więc nie ma (prawie) bez limitu, jak duże mogą one być.

Jeśli szukasz rozmiaru urządzenia, czyli 64- lub 32-bit, znalazłem this trick at 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 (całkowitymi dosyć mały zapisz w jednym słowie maszynowym), możesz zadzwonić pod numer 0.size, aby uzyskać liczbę bajtów. Przypuszczam, że powinno to być 4 na 32-bitowych kompilacjach, ale nie mogę tego teraz przetestować. Również największa Fixnum widocznie 2**30 - 1 (lub 2**62 - 1), ponieważ jeden bit jest używana aby oznaczyć go jako integer zamiast odwołania do obiektu.

+1

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

+0

Ups, myślę, że zacząłem za dużo myśleć o bajtach zamiast bitach. –

+10

OSTRZEŻENIE: Kod jest bezużyteczny. Przeczytaj edycję, zignoruj ​​kod. Nie znajdzie maksymalnego niczego dla Ruby. Znajduje kod, który nie używa oznaczonych wskaźników. –

11

Ruby Fixnums automatycznie przekształca się Bignums.

Aby znaleźć najwyższy Fixnum można 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 zgrane z ruby-talk discussion. Poszukaj tam więcej szczegółów.

+5

Jeśli użyjesz 'puts (Fixnum :: MAX + 1) .class', to nie zwróci' Bignum', jak mogłoby się wydawać. Jeśli zmienisz "8" na "16", to będzie. –

+0

to nie jest dostępne teraz – allenhwkim

12

Czytając przyjazną podręcznik? 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" 
+0

To wydaje się być jedyną odpowiedzią, która zwraca liczby na przejściu od Fixnum do Bignum, które dla mnie, oznacza, że ​​jest to największy Fixnum w Ruby. –

78
FIXNUM_MAX = (2**(0.size * 8 -2) -1) 
FIXNUM_MIN = -(2**(0.size * 8 -2)) 
+5

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

+27

@Matthias Dodatkowy bit jest używany do oznaczania wartości jako liczby całkowitej (w przeciwieństwie do wskaźnika do obiektu). –

+0

Interesujące, dzięki! – Matthias

0

jak @ Jörg W Mittag zauważył: w jruby, ustalić rozmiar num jest 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