Ruby max tamsayı


89

Ruby'de bir sistem maksimum tamsayısı belirleyebilmem gerekiyor. Nasıl ya da mümkün olup olmadığını bilen var mı?

Yanıtlar:


50

Ruby tam sayıları taştıklarında otomatik olarak büyük bir tamsayı sınıfa dönüştürür, bu nedenle (pratik olarak) ne kadar büyük olabileceklerine dair bir sınır yoktur.

Makinenin boyutunu, yani 64 veya 32 bit arıyorsanız, bu numarayı ruby-forum.com'da buldum :

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 nesnelerinin boyutunu (tek bir makine kelimesinde saklanacak kadar küçük tamsayılar) arıyorsanız 0.size, bayt sayısını öğrenmek için arayabilirsiniz . Sanırım 32 bitlik yapılarda 4 olmalı, ancak şu anda bunu test edemiyorum. Ayrıca, en büyük Fixnum görünüşe göre 2**30 - 1(veya 2**62 - 1) çünkü bir bit onu bir nesne referansı yerine bir tamsayı olarak işaretlemek için kullanılır.


1
2 ** (machine_size * 8) -1 istediğinizden oldukça eminim; 2 ** 4-1 = 15 ki bu çok büyük bir şey değildir.
Cebjyre

Hata, sanırım bitler yerine baytlar hakkında çok fazla düşünmeye başladım.
Matthew Crumley

10
UYARI: Kod işe yaramaz. Düzenlemeyi okuyun, kodu dikkate almayın. Ruby için maksimum hiçbir şeyi bulamıyor. Etiketli işaretçiler kullanmayan kod için bulur.
CJ.

şimdi (2018-01-21) pencerelerde 64 bit ruby'de bile 32 bit (diğer yandan cygwin'de uygun 64 bit var)
graywolf

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

5
İşaret için neden 1 yerine 2 bit çıkardınız? Bunu test ettim ve doğru görünüyor, ancak Ruby işaret için neden 2 bit kullanıyor?
Matthias

29
@Matthias Ekstra bir bit, değeri bir tamsayı olarak işaretlemek için kullanılır (bir nesneye yönelik bir işaretçinin aksine).
Matthew Crumley

2
En azından JRuby için bu doğru değil. JRuby olarak, Fixnumher zaman 64 Bit (değil 63 veya YARV gibi 31 bit) bakılmaksızın makine kelime büyüklüğü ve hiçbir etiket bit yoktur.
Jörg W Mittag

13

Dostça kılavuzu okuyor musunuz? Bunu kim yapmak ister?

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"

Bu, Fixnum'dan Bignum'a geçişte sayıları döndüren tek cevap gibi görünüyor, ki bu bana göre Ruby'deki en büyük Fixnum'dur.
The Tin Man

11

Ruby'de Fixnumlar otomatik olarak Bignums'a dönüştürülür.

Mümkün olan en yüksek Fixnum'u bulmak için aşağıdaki gibi bir şey yapabilirsiniz:

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)

Yakut konuşmalarından utanmazca koparılmış . Daha fazla ayrıntı için oraya bakın.


5
Bunu yaparsanız puts (Fixnum::MAX + 1).class, Bignumolması gerektiği gibi görünmez . Eğer değiştirirseniz 8için 16bunun olacaktır.
The Tin Man

1

Ruby 2.4'ten beri, Bignum ve Fixnum'un Tamsayı olarak birleşmesinden bu yana maksimum yoktur. bkz Özelliği # 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

Herhangi bir taşma olmayacak, ne olacak bir hafıza yetersizliği.


0

@ Jörg W Mittag'ın belirttiği gibi: jruby'de fix num size her zaman 8 bayt uzunluğundadır. Bu kod parçası gerçeği gösteriyor:

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
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.