Infinity in Elixir/Erlang?

I found there’s no builtin infinity, negative infinity and NaN in Elixir/Erlang. How do you solve this problem? I know I can use :infinity so that I can compare it and all numbers, but how about negative infinity and NaN?

2 Likes

There is neither. Even :infinity does only work by accident (term ordering).

1 Like

@tony612: as @NobbZ said there are no equivalents.

If you really need to have them then you need a small hack.

From Basic operators you can read about term ordering:

The reason we can compare different data types is pragmatism. Sorting algorithms don’t need to worry about different data types in order to sort. The overall sorting order is defined below:

number < atom < reference < function < port < pid < tuple < map < list < bitstring

Therefore you could use a hack like this one:

negative_infinity = {}
number = {0}
infinity = {:infinity}

negative_infinity < number
# true
number < infinity
# true

I’m not sure, but I think that comparing numbers should be faster than comparing them in tuples, so personally I don’t recommend them. At least for me comparing tuples is less clear.

The Elixir-way is to pattern-match them:

defmodule MyComparator do
  def compare(:infinity, :negative_infinity), do: :gt
  def compare(:infinity, number) when is_number(number), do: :gt
  def compare(:negative_infinity, :infinity), do: :lt
  def compare(:negative_infinity, number) when is_number(number), do: :lt
  def compare(number, :infinity) when is_number(number), do: :lt
  def compare(number, :negative_infinity) when is_number(number), do: :gt

  # def eq ...
  # def ge ...
  # def gt ...
  # def le ...
  # def lg ...
  # def ne ...
end

Similarly for NaN. In JavaScript expression: 0 / 0 returns NaN, but Elixir raises ArithmeticError.
From here you have two ways:

  1. try/rescue - use this only you don’t have any other way
  2. pattern matching - really recommend - it’s 100% Elixir-way
defmodule MyMath do
  def safe_div(_dividend, 0), do: {:error, :dividing_by_zero}
  def safe_div(dividend, divider), do: {:ok, dividend / divider}
end

# first_num = ...
# second_num = ...
case MyMath.safe_div(first_num, second_num) do
  {:ok, _result} -> IO.puts "Yeah!"
  {:error, _error} -> IO.puts "Oops!"
end

Is it what you are looking for?

4 Likes