Ruby Intro

SENG2021

Numbers

Like most (if not all) object oriented programming languages out there, Ruby has an Integer class and a Float class. Less common in standard libraries however, are the classes Rational and Complex which are used to represent fractions and complex numbers respectively.

Integers

In terms of functionality, there’s little interesting with Integers. There’s obviously adding, subtracting, multiplication, division, modulo and exponentials.

1
2
3
4
5
6
7
8
9
10
11
12
1 + 2
# 3
1 - 2
# -1 
1 * 2
# 2
2 / 1
# 2
5 % 2
# 1
2 ** 3
# 8

There are also several methods for common operations

1
2
3
4
5
6
7
8
1.next
# 2
1.even?
# false
10.gcd(2)
# 2
"10".to_i
# 10

Fixnum vs Bignum

To make an analogy to Java and C, this is the comparison between int and long. In Ruby however, integers are not actually of the class Integer.

What we think of Integer is the Fixnum. It’s used for all integers that would fit in a machine’s ‘word’, otherwise it’s a Bignum. Both these types inherit from the Integer class.

On this 64bit Mac, a word is 8 bytes. The class uses 1 bit mark the number as positive or negative, and another to mark the integer as value as opposed to a pointer (this is why object_id for Fixnum are always odd). As such, the maximum value for a Fixnum is 4611686018427387903 (262-1) and the minimum is -4611686018427387904 (-262). If an Fixnum leaves this range, Ruby automatically converts it to a Bignum and vice versa.

1
2
3
4
5
6
7
8
9
10
11
FIXNUM_MAX = (2**(0.size * 8 -2) -1)
# 4611686018427387903
FIXNUM_MIN = -(2**(0.size * 8 -2))
# -4611686018427387904
FIXNUM_MAX.class
# Fixnum
bignum = FIXNUM_MAX + 1
bignum.class
# Bignum
(bignum-1).class
# Fixnum

The biggest difference between these classes is that, like Java ints, Fixnum objects are immediate value. They are not references to another object. Remember in the last post when repeating "xyzxyz".object_id would return a different number everytime? This won’t be the case for Fixnum. In fact, object_id of Fixnum are predictable. For positive numbers, the id is simply 2 * value + 1. Similarly, 2 * value – 1 for negative numbers.

1
2
3
4
5
6
7
4611686018427387903.object_id
# 9223372036854775807
4611686018427387903.object_id
# 9223372036854775807

-4611686018427387904.object_id
# -9223372036854775807

Rationals

Rationals are useful for calculations because they come with the accuracy that’s missing from floats. There are 3 ways to create them

1
2
3
4
5
6
7
8
9
10
11
Rational(1, 2)
# (1/2)
"1/2".to_r
# (1/2)
0.5.rationalize
# (1/2)

Rational(1,2) + Rational(2,3)
# (7/6)
Rational(7,6).to_f
# 1.1666666666666667

Float

Like integers, Float’s methods are quite standard.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
1.2345.to_i
# 1
1.2345.floor
# 1
9.87654321.round(3)
# 9.877
(0.0).infinite?
# nil
(-1.0/0.0).infinite?
# -1
(+1.0/0.0).infinite?
# 1
0.3.rationalize
# (3/10)

However, it’s important to note that floating point calculations are inaccurate, like almost every programming language (can’t name any that are accurate).

1
2
3
4
0.3.to_r
# (5404319552844595/18014398509481984)
printf("%.55f\n", 1.9)
1.8999999999999999111821580299874767661094665527343750000
  1. Ruby-Docs Integer
  2. Ruby-Docs Fixnum
  3. Ruby-Dics Bignum
  4. Ruby-Docs Float
  5. Ruby-Docs Rationals
  6. Ruby-Docs Complex
  7. Stack Overflow Ruby max integer