Integer Ruby maks


89

Saya harus dapat menentukan integer maksimum sistem di Ruby. Ada yang tahu caranya, atau apakah itu mungkin?

Jawaban:


50

Ruby secara otomatis mengonversi bilangan bulat menjadi kelas bilangan bulat besar ketika mereka melimpah, jadi (secara praktis) tidak ada batasan seberapa besar mereka bisa.

Jika Anda mencari ukuran mesin, yaitu 64- atau 32-bit, saya menemukan trik ini di 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

Jika Anda mencari ukuran objek Fixnum (bilangan bulat yang cukup kecil untuk disimpan dalam satu kata mesin), Anda dapat memanggil 0.sizeuntuk mendapatkan jumlah byte. Saya kira itu harus 4 pada build 32-bit, tetapi saya tidak dapat mengujinya sekarang. Juga, Fixnum terbesar ternyata 2**30 - 1(atau 2**62 - 1), karena satu bit digunakan untuk menandainya sebagai integer alih-alih referensi objek.


1
Cukup yakin Anda ingin 2 ** (ukuran_mesin * 8) -1; 2 ** 4-1 = 15 yang bukan merupakan sesuatu yang sangat besar.
Cebjyre

Ups, saya rasa saya mulai berpikir terlalu banyak tentang byte, bukan bit.
Matthew Crumley

10
PERINGATAN: Kode tidak berguna. Baca edit, abaikan kodenya. Itu tidak menemukan apa pun yang maksimal untuk Ruby. Ia menemukannya untuk kode yang tidak menggunakan penunjuk yang diberi tag.
CJ.

sekarang (21-01-2018) 32 bit bahkan di 64bit ruby ​​di windows (cygwin memiliki 64bit yang tepat di sisi lain)
graywolf

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

5
Mengapa Anda mengurangi 2 bit, bukan 1 untuk tanda? Saya menguji ini dan tampaknya benar, tetapi mengapa Ruby menggunakan 2 bit untuk tanda?
Matthias

29
@Matthias Bit ekstra digunakan untuk menandai nilai sebagai integer (sebagai lawan penunjuk ke objek).
Matthew Crumley

2
Ini tidak benar untuk JRuby, setidaknya. Di JRuby, Fixnumselalu 64 Bit (bukan 63 atau 31 bit seperti di YARV) terlepas dari ukuran kata mesin, dan tidak ada bit tag.
Jörg W Mittag

13

Membaca manual ramah? Siapa yang mau melakukan itu?

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"

Tampaknya ini adalah satu-satunya jawaban yang mengembalikan angka pada transisi dari Fixnum ke Bignum, yang bagi saya berarti itu adalah Fixnum terbesar di Ruby.
Manusia Timah

11

Dalam ruby ​​Fixnums secara otomatis diubah menjadi Bignum.

Untuk menemukan Fixnum setinggi mungkin, Anda dapat melakukan sesuatu seperti ini:

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)

Merobek tanpa malu-malu dari diskusi ruby-talk . Lihat di sana untuk lebih jelasnya.


5
Jika Anda melakukan puts (Fixnum::MAX + 1).classini tidak kembali Bignumseperti yang seharusnya. Jika Anda mengubah 8ke 16itu akan.
Tin Man

1

Tidak ada jumlah maksimum sejak Ruby 2.4, karena Bignum dan Fixnum disatukan menjadi Integer. lihat Fitur # 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

Tidak akan ada luapan apapun, yang akan terjadi adalah kehabisan memori.


0

seperti yang ditunjukkan @ Jörg W Mittag: dalam jruby, ukuran nomor tetap selalu sepanjang 8 byte. Cuplikan kode ini menunjukkan kebenaran:

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
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.