Số nguyên tối đa của Ruby


87

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:


49

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.


1
Khá chắc chắn bạn muốn 2 ** (machine_size * 8) -1; 2 ** 4-1 = 15 không lớn lắm.
Cebjyre

Rất tiếc, tôi đoán tôi đã bắt đầu nghĩ quá nhiều về byte thay vì bit.
Matthew Crumley 11/02/09

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

bây giờ (2018/01/21) đó là 32bits ngay cả trong 64bit ruby trên cửa sổ (Cygwin có 64bit thích hợp trên Mặt khác)
graywolf

81
FIXNUM_MAX = (2**(0.size * 8 -2) -1)
FIXNUM_MIN = -(2**(0.size * 8 -2))

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

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

2
Điều này không đúng với JRuby, ít nhất. Trong JRuby, Fixnumluô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ẻ.
Jörg W Mittag,

13

Đọ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"

Đây dường như là câu trả lời duy nhất trả về các số khi chuyển đổi từ Fixnum sang Bignum, đối với tôi, nó có nghĩa là Fixnum lớn nhất trong Ruby.
the Tin Man,

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 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.


5
Nếu bạn làm puts (Fixnum::MAX + 1).classđiều này không trở lại Bignumnhư nó có vẻ như nó phải. Nếu bạn thay đổi 8để 16nó sẽ.
the Tin Man

cái này hiện không khả dụng
allenhwkim

1

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ớ.


0

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
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.