Let’s start by taking a look at the class hierarchy of all the number related classes in Ruby:
Numeric # Parent for all of the number classes.
Integer # Object representing integer numbers.
Float # Object representing imprecise decimal numbers.
Complex # Object representing imaginary numbers.
Rational # Object representing rational numbers (fractions, in simple words).
BigDecimal # Object providing arbitrary-precision floating-point decimal arithmetic. It's part of Ruby Standard Library.
Numeric
https://ruby-doc.org/core-3.1.2/Numeric.html
Numeric is the class from which all higher-level numeric classes should inherit.
Integer
https://ruby-doc.org/core-3.1.2/Integer.html
An Integer object represent math integer value:
>> Integer(1)
=> (1)
Let’s check hierarchy. ancestors
method gets parent classes and modules, and as we don’t need modules we’ll substact them:
>> Integer.ancestors - Integer.included_modules
=> [Integer, Numeric, Object, BasicObject]
There were Fixnum & Bignum before Ruby 2.4 unified Fixnum & Bignum into the same class (Integer) in 2016:
- https://www.ruby-lang.org/en/news/2016/12/25/ruby-2-4-0-released/
- https://bugs.ruby-lang.org/issues/12005
Actucally, you still can see hierarchy, but will see “Integer” as current class:
>> Fixnum.ancestors - Fixnum.included_modules
=> [Integer, Numeric, Object, BasicObject]
Why do we need different classes? It’s Ruby implementation detail for optimization purpose. The same optimizations still exist, but it’s compiler optimization, i.e. behind the scenes, invisible to the programmer. Basically, Fixnums are fast and Bignums are slower, and the implementation automatically switches back and forth between them. Since Ruby 2.4 you don’t ask Fixnum or Bignum, you just get one or the other, depending on whether your integer fits into the restricted size of a Fixnum or not.
Float
https://ruby-doc.org/core-3.1.2/Float.html
Ruby docs says about Float:
A Float object represents a sometimes-inexact real number using the native architecture’s double-precision floating point representation. https://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html
This is not Ruby’s fault. Floats in general suffer from this type of rounding error, for example:
>> (1.0-0.1) == 0.9
=> false
Complex
- https://ruby-doc.org/core-3.1.2/Complex.html
- https://en.wikipedia.org/wiki/Complex_number
- https://www.youtube.com/watch?v=SP-YJe7Vldo
- https://www.youtube.com/watch?v=cUzklzVXJwo
- https://www.youtube.com/watch?v=5PcpBw5Hbwo
In math there is a concept of Complex numbers. Complex numbers are the numbers that are expressed in the form of a+ib
where, a
,b
are real numbers and i
is an imaginary number. Complex
object is used to represent this mathematical concept in Ruby.
>> Complex(1)
=> (1+0i)
Rational
It’s an object to represent mathematical rational numbers. A rational number is a number that can be represented as a pair of integer numbers: a/b
(b
> 0), where a
is the numerator and b
is the denominator. Integer number a
equals rational number a/1
mathematically.
>> Rational(1)
=> (1/1)
BigDecimal
https://ruby-doc.org/stdlib-3.1.2/libdoc/bigdecimal/rdoc/BigDecimal.html
BigDecimal provides arbitrary-precision floating-point decimal arithmetic.
>> BigDecimal(1)
=> 0.1e1