Ruby max Ganzzahl

86

Ich muss in der Lage sein, eine maximale System-Ganzzahl in Ruby zu bestimmen. Weiß jemand wie oder ob es möglich ist?

Allyn
quelle

Antworten:

49

Ruby konvertiert Ganzzahlen automatisch in eine große Ganzzahlklasse, wenn sie überlaufen, sodass ihre Größe (praktisch) unbegrenzt ist.

Wenn Sie nach der Größe des Computers suchen, dh 64- oder 32-Bit, habe ich diesen Trick bei ruby-forum.com gefunden :

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

Wenn Sie nach der Größe von Fixnum-Objekten suchen (Ganzzahlen, die klein genug sind, um in einem einzelnen Maschinenwort gespeichert zu werden), können 0.sizeSie die Anzahl der Bytes abrufen . Ich würde vermuten, dass es bei 32-Bit-Builds 4 sein sollte, aber das kann ich momentan nicht testen. Das größte Fixnum ist anscheinend 2**30 - 1(oder 2**62 - 1), da ein Bit verwendet wird, um es als Ganzzahl anstelle einer Objektreferenz zu markieren.

Matthew Crumley
quelle
1
Ziemlich sicher, dass Sie 2 ** (machine_size * 8) -1 wollen; 2 ** 4-1 = 15, was nichts sehr Großes ist.
Cebjyre
Hoppla, ich glaube, ich habe angefangen, zu viel über Bytes statt über Bits nachzudenken.
Matthew Crumley
10
WARNUNG: Der Code ist unbrauchbar. Lesen Sie die Bearbeitung, ignorieren Sie den Code. Es findet nicht das Maximum für Ruby. Es findet es für Code, der keine markierten Zeiger verwendet.
CJ.
Jetzt (2018-01-21) sind es 32 Bit, sogar in 64-Bit-Ruby unter Windows (Cygwin hat auf der anderen Seite die richtigen 64-Bit)
Graywolf
81
FIXNUM_MAX = (2**(0.size * 8 -2) -1)
FIXNUM_MIN = -(2**(0.size * 8 -2))

quelle
5
Warum haben Sie 2 Bits anstelle von 1 für das Vorzeichen subtrahiert? Ich habe dies getestet und es scheint korrekt zu sein, aber warum verwendet Ruby 2 Bits für das Zeichen?
Matthias
29
@Matthias Ein zusätzliches Bit wird verwendet, um den Wert als Ganzzahl zu markieren (im Gegensatz zu einem Zeiger auf ein Objekt).
Matthew Crumley
2
Dies gilt zumindest nicht für JRuby. In JRuby Fixnumist immer 64 Bit (nicht 63 oder 31 Bit wie in YARV), unabhängig von der Größe des Maschinenworts, und es gibt kein Tag-Bit.
Jörg W Mittag
13

Das freundliche Handbuch lesen? Wer würde das machen wollen?

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
quelle
Dies scheint die einzige Antwort zu sein, die beim Übergang von Fixnum zu Bignum Zahlen zurückgibt, was für mich bedeutet, dass dies das größte Fixnum in Ruby ist.
der Blechmann
11

In Ruby werden Fixnums automatisch in Bignums konvertiert.

Um das höchstmögliche Fixnum zu finden, können Sie Folgendes tun:

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)

Schamlos aus einer Ruby-Talk-Diskussion herausgerissen . Suchen Sie dort nach weiteren Details.

tommym
quelle
5
Wenn Sie dies tun, puts (Fixnum::MAX + 1).classkehrt dies nicht so zurück, Bignumwie es scheint. Wenn Sie dazu wechseln 8, 16wird.
der Blechmann
Dies ist jetzt nicht verfügbar
Allenhwkim
1

Seit Ruby 2.4 gibt es kein Maximum mehr, da Bignum und Fixnum zu Integer vereinigt wurden. siehe Feature # 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

Es wird keinen Überlauf geben, was passieren würde, ist ein Mangel an Speicher.

estani
quelle
0

wie @ Jörg W Mittag betonte: In jruby ist die Größe der festen Nummer immer 8 Byte lang. Dieses Code-Snippet zeigt die Wahrheit:

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
quelle