Tôi cần có thể xác định một số nguyên tối đa của hệ thống trong Ruby. Có ai biết cách làm hoặc nếu có thể?
Câu trả lời:
Ruby tự động chuyển đổi số nguyên thành một lớp số nguyên lớn khi chúng bị tràn, vì vậy (thực tế) không có giới hạn về kích thước 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 đã tìm thấy thủ thuật này tại 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 (các số nguyên đủ nhỏ để lưu trữ trong một từ máy), bạn có thể gọi 0.size
để lấy số byte. Tôi đoán nó phải là 4 trên bản dựng 32-bit, nhưng tôi không thể kiểm tra điều đó ngay bây giờ. Ngoài ra, Fixnum lớn nhất dường như là 2**30 - 1
(hoặc 2**62 - 1
), vì một bit được sử dụng để đánh dấu nó là số nguyên thay vì tham chiếu đối tượng.
FIXNUM_MAX = (2**(0.size * 8 -2) -1)
FIXNUM_MIN = -(2**(0.size * 8 -2))
Fixnum
luôn luôn là 64 Bit (không phải 63 hoặc 31 bit như trong YARV) bất kể kích thước từ máy và không có bit thẻ.
Đọc hướng dẫn thân thiện? Ai muốn làm điều đó?
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"
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 như sau:
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)
Không biết xấu hổ đã xé toạc một cuộc thảo luận về ruby . Nhìn vào đó để biết thêm chi tiết.
puts (Fixnum::MAX + 1).class
điều này không trở lại Bignum
như nó có vẻ như nó phải. Nếu bạn thay đổi 8
để 16
nó sẽ.
Không có mức tối đa kể từ Ruby 2.4, vì Bignum và Fixnum đã hợp nhất thành Integer. xem Tính năng # 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
Sẽ không có bất kỳ sự cố tràn nào, những gì sẽ xảy ra là hết bộ nhớ.
như @ Jörg W Mittag đã chỉ ra: trong jruby, kích thước num sửa chữa luôn 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