2009-02-11 75 views
71

Tôi cần có khả năng xác định số nguyên tối đa của hệ thống trong Ruby. Ai biết làm thế nào, hoặc nếu nó có thể?Số nguyên tối đa Ruby

Trả lời

42

Ruby tự động chuyển đổi số nguyên thành một lớp số nguyên lớn khi chúng tràn, do đó, (thực tế) không có giới hạn về mức độ lớn của chúng.

Nếu bạn đang tìm kiếm kích thước của máy, tức là 64 hoặc 32-bit, tôi thấy 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 

Nếu bạn đang tìm kiếm kích thước của các đối tượng Fixnum (số nguyên đủ để nhỏ lưu trữ trong một từ máy), bạn có thể gọi 0.size để nhận số byte. Tôi đoán nó sẽ là 4 trên 32-bit, nhưng tôi không thể kiểm tra ngay bây giờ. Ngoài ra, Fixnum lớn nhất rõ ràng là 2**30 - 1 (hoặc 2**62 - 1), bởi vì một bit được sử dụng để đánh dấu nó như là một số nguyên thay vì một tham chiếu đối tượng.

+1

Khá chắc chắn bạn muốn 2 ** (machine_size * 8) -1; 2 ** 4-1 = 15 không phải là một thứ rất lớn. – Cebjyre

+0

Rất tiếc, tôi đoán tôi đã bắt đầu suy nghĩ quá nhiều về byte thay vì bit. –

+10

CẢNH BÁO: Mã này vô dụng. Đọc chỉnh sửa, bỏ qua mã. Nó không tìm thấy bất cứ thứ gì tối đa cho Ruby. Nó tìm thấy nó cho mã mà không sử dụng con trỏ được gắn thẻ. –

11

Trong ruby ​​Fixnums được tự động chuyển đổi thành Bignums.

Để tìm Fixnum cao nhất có thể bạn có thể làm một cái gì đó như thế này:

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) 

shamelessly tách từ một ruby-talk discussion. Nhìn ở đó để biết thêm chi tiết.

+5

Nếu bạn đặt 'đặt (Fixnum :: MAX + 1) .class' này không trả về' Bignum' giống như nó có vẻ như cần. Nếu bạn thay đổi '8' thành' 16' nó sẽ. –

+0

tính năng này hiện không khả dụng – allenhwkim

12

Đọc hướng dẫn sử dụng thân thiện? Ai muốn làm vậy?

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

Điều này có vẻ là câu trả lời duy nhất trả về số khi chuyển từ Fixnum sang Bignum, với tôi, có nghĩa là Fixnum lớn nhất trong Ruby. –

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

Tại sao bạn trừ 2 bit thay vì 1 cho dấu? Tôi đã thử nghiệm này và nó có vẻ là chính xác, nhưng tại sao Ruby sử dụng 2 bit cho các dấu hiệu? – Matthias

+27

@Matthias Một bit phụ được sử dụng để đánh dấu giá trị dưới dạng số nguyên (ngược với một con trỏ đến một đối tượng). –

+0

Thú vị, cảm ơn! – Matthias

0

như @ Jörg W Mittag chỉ ra: trong JRuby, sửa kích thước num luôn có chiều dài 8 byte. Đoạn mã này cho thấy sự thật:

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 
Các vấn đề liên quan