Ruby uses a handful of classes to represent numbers. I had trouble remembering
the exact class hierarchy1, so I opened up
irb to inspect the ancestors
of each class. The hierarchy turned out to be simpler than I expected and
actually not that hard to remember once laid out:
Bignum have been unified into
Integer in Ruby 2.4 and
are planned to be deprecated in the future. See Unify Fixnum and Bignum into
Everything starts with the
Numeric superclass, which
also includes the
There are four basic types:
Each can be constructed in at least the following ways: with literals,
conversion methods defined on
Object and capitalized conversion
methods defined on
Floating point representation is only an approximation of real
numbers. In order to represent very large or very accurate
floating point numbers in Ruby, we have to resort to
Decimal arithmetic is also useful for general calculation, because it provides the correct answers people expect–whereas normal binary floating point arithmetic often introduces subtle errors because of the conversion between base 10 and base 2.
Update: This chapter only applies to Ruby versions before 2.4. (#12005)
Ruby uses instances of these two classes to represent integers. The
interesting part is that we never actually create
Behind the scenes, Ruby juggles between
Bignum, depending on
the size of the number we want to reference.
You can verify this in irb:
The automatic conversion is also mentioned in the documentation for
[Fixnum] holds Integer values that can be represented in a native machine word (minus 1 bit). If any operation on a Fixnum exceeds this range, the value is automatically converted to a Bignum. Fixnum objects have immediate value. This means that when they are assigned or passed as parameters, the actual object is passed, rather than a reference to that object. Assignment does not alias Fixnum objects. There is effectively only one Fixnum object instance for any given integer value, so, for example, you cannot add a singleton method to a Fixnum. Any attempt to add a singleton method to a Fixnum object will raise a TypeError.
Unsurprisingly, the documentation for
Bignum is similar:
Bignum objects hold integers outside the range of Fixnum. Bignum objects are created automatically when integer calculations would otherwise overflow a Fixnum. When a calculation involving Bignum objects returns a result that will fit in a Fixnum, the result is automatically converted. For the purposes of the bitwise operations and , a Bignum is treated as if it were an infinite-length bitstring with 2’s complement representation. While Fixnum values are immediate, Bignum objects are not—assignment and parameter passing work with references to objects, not the objects themselves.
Wait, what was that last bit?
Bignum seem to behave differently when it comes to memory allocation. Let’s try to confirm this:
The object ids differ, showing that the two variables point to different objects. Fixnum instances show the opposite behaviour:
Don’t forget to
require "bigdecimal". ↩
BigDecimal is the only numeric class in Ruby that can be instantiated with a constructor method, e.g.:
BigDecimal.new("1.2") — note that the argument is passed as a string to work around the imprecise nature of floats. ↩