Ruby max integer
Asked Answered
G

6

99

I need to be able to determine a systems maximum integer in Ruby. Anybody know how, or if it's possible?

Gapes answered 11/2, 2009 at 7:3 Comment(0)
T
55

Ruby automatically converts integers to a large integer class when they overflow, so there's (practically) no limit to how big they can be.

If you are looking for the machine's size, i.e. 64- or 32-bit, I found this trick at 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

If you are looking for the size of Fixnum objects (integers small enough to store in a single machine word), you can call 0.size to get the number of bytes. I would guess it should be 4 on 32-bit builds, but I can't test that right now. Also, the largest Fixnum is apparently 2**30 - 1 (or 2**62 - 1), because one bit is used to mark it as an integer instead of an object reference.

Teatime answered 11/2, 2009 at 7:23 Comment(4)
Pretty sure you want 2**(machine_size * 8) -1; 2**4-1=15 which is not a very large anything.Beuthen
Whoops, I guess I started thinking too much about bytes instead of bits.Teatime
WARNING: The code is useless. Read the edit, ignore the code. It doesn't find the maximum anything for Ruby. It finds it for code that does not use tagged pointers.Depilate
now (2018-01-21) it's 32bits even in 64bit ruby on windows (cygwin has proper 64bit on other hand)Regenerative
P
84
FIXNUM_MAX = (2**(0.size * 8 -2) -1)
FIXNUM_MIN = -(2**(0.size * 8 -2))
Persuasion answered 10/4, 2009 at 0:12 Comment(4)
Why did you subtract 2 bits instead of 1 for the sign? I tested this and it seems to be correct, but why does Ruby use 2 bits for the sign?Birdcage
@Matthias An extra bit is used to mark the value as an integer (as opposed to a pointer to an object).Teatime
This is not true for JRuby, at least. In JRuby, Fixnum is always 64 Bit (not 63 or 31 bit like in YARV) regardless of machine word size, and there is no tag bit.Megasporophyll
@Matthias [Old question, maybe you have the answer now, but...] signed integers in almost every language use "Two's Compliment" representation. The range is -2**(n-1) up to 2**(n-1)-1 because the interpretation of the bits accounts for the sign, which uses a bit. (The positive maxvalue is smaller than the negative abs(minvalue), because one of its bit patterns represents 0, so it "gives up" a value the negative range doesn't.) If a Ruby implementations uses tagged ints, it only uses one extra bit for tracking whether the value fits in a register or if it needs an allocated object.Birdt
T
55

Ruby automatically converts integers to a large integer class when they overflow, so there's (practically) no limit to how big they can be.

If you are looking for the machine's size, i.e. 64- or 32-bit, I found this trick at 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

If you are looking for the size of Fixnum objects (integers small enough to store in a single machine word), you can call 0.size to get the number of bytes. I would guess it should be 4 on 32-bit builds, but I can't test that right now. Also, the largest Fixnum is apparently 2**30 - 1 (or 2**62 - 1), because one bit is used to mark it as an integer instead of an object reference.

Teatime answered 11/2, 2009 at 7:23 Comment(4)
Pretty sure you want 2**(machine_size * 8) -1; 2**4-1=15 which is not a very large anything.Beuthen
Whoops, I guess I started thinking too much about bytes instead of bits.Teatime
WARNING: The code is useless. Read the edit, ignore the code. It doesn't find the maximum anything for Ruby. It finds it for code that does not use tagged pointers.Depilate
now (2018-01-21) it's 32bits even in 64bit ruby on windows (cygwin has proper 64bit on other hand)Regenerative
G
13

Reading the friendly manual? Who'd want to do that?

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"
Galingale answered 11/2, 2009 at 23:59 Comment(1)
This seems to be the only answer that returns numbers at the transition from Fixnum to Bignum, which, to me, means that is the largest Fixnum in Ruby.Tomy
S
11

In ruby Fixnums are automatically converted to Bignums.

To find the highest possible Fixnum you could do something like this:

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)

Shamelessly ripped from a ruby-talk discussion. Look there for more details.

Saenz answered 11/2, 2009 at 7:18 Comment(1)
If you do puts (Fixnum::MAX + 1).class this doesn't return Bignum like it seems like it should. If you change 8 to 16 it will.Tomy
S
4

There is no maximum since Ruby 2.4, as Bignum and Fixnum got unified into Integer. see 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

There won't be any overflow, what would happen is an out of memory.

Straphanger answered 24/3, 2020 at 10:6 Comment(0)
C
0

as @Jörg W Mittag pointed out: in jruby, fix num size is always 8 bytes long. This code snippet shows the truth:

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
Coracoid answered 27/3, 2017 at 7:42 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.