01 May, 2022

Ruby

Numbers in Ruby

Let’s take a look at all number related classes in Ruby.

MROY Team

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:

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

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