Integer Ruby maks

89

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

Allyn
sumber

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.

Matthew Crumley
sumber
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))

sumber
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"
Andrew Grimm
sumber
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.

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

estani
sumber
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
Hailong Cao
sumber