Have you ever wondered how Ruby handles infinity? We’ve all run into the divide-by-zero error when diving an integer by zero, but things are different in case of floating point numbers.

1 / 0 #=> ZeroDivisionError 1.0 / 0 #=> Infinity 1 / 0.0 #=> Infinity Infinity #=> NameError: uninitialized constant Infinity

As you can see above, Ruby gives you a value that represents infinity when a floating point operation returns an infinite value.

There isn’t a constant with the name Infinity , as shown by the NameError that we encountered when trying to access it directly. But it is available as the constant Float::INFINITY . Let’s take a closer look at it.

Inf = 1 / 0.0 #=> Infinity Inf . class #=> Float Float :: INFINITY #=> Infinity # Negative infinity - 1.0 / 0 #=> -Infinity

Ok, now that we know that it’s a value of type Float, let’s try some arithmetic operations on it.

Inf = 1.0 / 0 #=> Infinity Inf + 42 #=> Infinity Inf / 42 #=> Infinity Inf - 42 #=> Infinity Inf * 42 #=> Infinity # Addition/multiplication of two infinite values also results in infinity Inf = 1.0 / 0 #=> Infinity Inf + Inf #=> Infinity Inf * Inf #=> Infinity # Comparisons Inf > 0 #=> true Inf == Inf #=> true Inf != Inf #=> false # Large float operations result in infinity 2 ** 10000 #=> big number with 3011 digits 2 ** 10000 + 0.1 #=> Infinity # Check if a number is infinite Inf . infinite? #=> true ( 1.0 ). infinite? #=> false

NaN - not a number

Subtraction and division of two infinite values yield undefined results. Now we have another kind of value, NaN , to represent such values. Let’s dig into NaN for a minute.

Inf - Inf #=> NaN Inf / Inf #=> NaN nan = 0 / 0.0 #=> NaN nan . class #=> Float Float :: NAN #=> NaN # Any arithmetic operation returns a NaN nan + nan #=> NaN nan - 42 #=> NaN # There's even a method to test if a value is NaN nan . nan? #=> True

Infinite ranges

One interesting use of Infinity is to get infinite ranges.

Inf = 1.0 / 0 ( 0 .. Inf ). take ( 5 ) #=> [0, 1, 2, 3, 4] ( 0 .. Inf ). include? ( 3 ) #=> true ( 0 .. Inf ). include? ( - 3 ) #=> false

You need to be careful when using methods like #select because you might end up with an infinite loop while #select keeps checking every number because it never reaches Infinity .

In such cases, you can use the Enumerable#lazy method to create a lazy enumerator and then use the #first method to take a certain number of items from that list.

( 0 .. 1 / 0.0 ). lazy . select ( & :even? ) . first ( 5 ) #=> [0, 2, 4, 6, 8]

An example

Let’s look at an situation where we might find infinite ranges useful. You have an Article class, and need to implement a within_word_limit? method that checks if the word count is between @min_word_count and @max_word_count .

If either of those variables is nil, that limit does not exist, ie. the range would be 0..Infinity . Here’s one way of doing it by setting the upper limit of the range as infinity.

class Article def within_word_limit? ( min_word_limit .. max_word_limit ). include? ( word_count ) end private def max_word_limit @max_word_limit || Float :: INFINITY end def min_word_limit @min_word_limit || 0 end def word_count # count words end end

We could do this by using the comparison operators and if statements, but using a range makes it much more readable.