จำนวนเต็มสูงสุดของ Ruby


90

ฉันจำเป็นต้องสามารถกำหนดจำนวนเต็มสูงสุดของระบบใน Ruby ใครรู้วิธีหรือถ้าเป็นไปได้?

คำตอบ:


50

Ruby จะแปลงจำนวนเต็มเป็นคลาสจำนวนเต็มขนาดใหญ่โดยอัตโนมัติเมื่อมันล้นดังนั้นจึงไม่มีข้อ จำกัด (ในทางปฏิบัติ) ว่าจะใหญ่แค่ไหน

หากคุณกำลังมองหาขนาดของเครื่องเช่น 64- หรือ 32 บิตฉันพบเคล็ดลับนี้ที่ 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

หากคุณกำลังมองหาขนาดของอ็อบเจ็กต์ Fixnum (จำนวนเต็มเล็กพอที่จะจัดเก็บในเครื่องคำเดียว) คุณสามารถโทร0.sizeเพื่อรับจำนวนไบต์ได้ ฉันเดาว่ามันควรจะเป็น 4 ในรุ่น 32 บิต แต่ฉันไม่สามารถทดสอบได้ในตอนนี้ นอกจากนี้ Fixnum ที่ใหญ่ที่สุดยังเห็นได้ชัด2**30 - 1(หรือ2**62 - 1) เนื่องจากมีการใช้หนึ่งบิตเพื่อทำเครื่องหมายเป็นจำนวนเต็มแทนที่จะเป็นการอ้างอิงวัตถุ


1
ค่อนข้างแน่ใจว่าคุณต้องการ 2 ** (machine_size * 8) -1; 2 ** 4-1 = 15 ซึ่งไม่ได้ใหญ่โตอะไร
Cebjyre

อ๊ะฉันเดาว่าฉันเริ่มคิดมากเกินไปเกี่ยวกับไบต์แทนที่จะเป็นบิต
Matthew Crumley

10
คำเตือน: รหัสนี้ไม่มีประโยชน์ อ่านการแก้ไขไม่สนใจรหัส ไม่พบสิ่งใดสูงสุดสำหรับ Ruby พบว่าเป็นรหัสที่ไม่ใช้พอยน์เตอร์ที่ติดแท็ก
CJ.

ตอนนี้ (2018-01-21) เป็น 32 บิตแม้ในทับทิม 64 บิตบน windows (cygwin มี 64 บิตที่เหมาะสมในทางกลับกัน)
graywolf

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

5
เหตุใดคุณจึงลบ 2 บิตแทนที่จะเป็น 1 สำหรับเครื่องหมาย ฉันทดสอบสิ่งนี้และดูเหมือนว่าจะถูกต้อง แต่ทำไม Ruby ถึงใช้ 2 บิตสำหรับเครื่องหมาย?
Matthias

29
@ Matthias บิตพิเศษใช้เพื่อทำเครื่องหมายค่าเป็นจำนวนเต็ม (ตรงข้ามกับตัวชี้ไปยังวัตถุ)
Matthew Crumley

2
นี่ไม่เป็นความจริงสำหรับ JRuby อย่างน้อย ใน JRuby Fixnumจะเป็น 64 บิตเสมอ (ไม่ใช่ 63 หรือ 31 บิตเหมือนใน YARV) โดยไม่คำนึงถึงขนาดคำของเครื่องและไม่มีบิตแท็ก
Jörg W Mittag

13

อ่านคู่มือที่เป็นมิตร? ใครอยากทำแบบนั้น?

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"

นี่ดูเหมือนจะเป็นคำตอบเดียวที่ส่งคืนตัวเลขเมื่อเปลี่ยนจาก Fixnum เป็น Bignum ซึ่งสำหรับฉันหมายความว่าเป็น Fixnum ที่ใหญ่ที่สุดใน Ruby
คนดีบุก

11

ใน Ruby Fixnums จะถูกแปลงเป็น Bignums โดยอัตโนมัติ

หากต้องการค้นหา Fixnum สูงสุดที่เป็นไปได้คุณสามารถทำสิ่งนี้:

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)

ลงคอฉีกจากการอภิปรายทับทิมพูดคุย ดูรายละเอียดเพิ่มเติม


5
หากคุณทำเช่นputs (Fixnum::MAX + 1).classนี้ไม่ได้ผลBignumอย่างที่ควรจะเป็น ถ้าคุณเปลี่ยน8ไป16ก็จะ
คนดีบุก

1

ไม่มีค่าสูงสุดตั้งแต่ Ruby 2.4 เนื่องจาก Bignum และ Fixnum รวมกันเป็น Integer ดูคุณลักษณะ # 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

จะไม่มีสิ่งใดล้นสิ่งที่จะเกิดขึ้นคือความทรงจำไม่เพียงพอ


0

ดังที่ @ Jörg W Mittag ชี้ให้เห็น: ใน jruby ขนาดฟิกซ์ num จะยาว 8 ไบต์เสมอ ข้อมูลโค้ดนี้แสดงความจริง:

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
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.