Elixir : Basics of Float datatype
The Float data type in elixir, just like any other language, represents real numbers. Defining a floating point number in elixir requires a decimal separator .
and at least a single digit before and after the separator. Elixir also supports scientific notation syntax for defining the floating point numbers. Similar to integers in elixir, you can use an underscore to increase the readability of the number.
a = -123.123_123 # -123.123123
b = 1.23e-5 # 0.0000123
Operators
Float supports all the arithmetic operators, +
, -
, *
and /
, the exponentiation operator **
, the comparison operators, ==
, ===
, !=
, !==
, <
, >
, <=
and >=
and the logical operators &&
, ||
, and !
, similar to the integer datatype. When mixing integers and floats in an arithmetic expression, the result will always be a floating point number.
1 + 3.0 # 4.0
10.0 * 2 # 20.0
IEEE 754
Elixir follows IEEE 754 double precision-64 bit representation of floating point numbers and this gives you about 15 digits of precision before the digits are rounded and approximated. Floating point numbers, when represented using finite bits, cannot accurately represent all the numbers with complete precision. This is a common issue in all programming languages.
0.0000000123456789123456789 # 1.234567891234568e-8 - 15 digits of precision
12345678.123456789123456 # 12345678.12345679 - 15 digits of precision
Only the fractions with denominator as 2ⁿ such as 1/2, 3/4, 5/8 etc can be accurately stored in binary representation using the float data type. The rest of the fractions(e.g. 1/3 = 0.33333….) have values which are continuously and infinitely recurring and hence these fractions must be truncated into the available finite bits, causing rounding errors in floating point representation. Please note that when comparing floating point numbers, in certain cases, the results would not be as expected due to the rounding error. Thus it is advised to use tolerance or epsilon value of your preferred precision, when comparing two floating point numbers.
a = 0.1 + 0.2 # 0.30000000000000004
a == 0.3 # false
tolerance = 0.00000000001
abs(a - 0.3) < tolerance # true
Reference modules
Floating point numbers have their reference module Float, which offers functions such as ceil, floor and round etc. Erlang’s :math module offers numerous mathematical functions such as sqrt, tan, sin, log etc. The maximum and minimum finite numbers that the elixir’s float datatype can represent, can be identified by using the functions max_infinite and min_infinite of the Float module. If any of the arithmetic operations such as multiplication yields a number that falls outside this range, then elixir will throw an arithmetic error.
Float.max_finite() * 2
** (ArithmeticError) bad argument in arithmetic expression: 1.7976931348623157e308 * 2
:erlang.*(1.7976931348623157e308, 2)
iex:168: (file)
If you require floating point numbers of a higher range and precision, libraries such as decimal, which offers arbitrary decimal precision, can be used instead of the built-in float datatype. These libraries represent floating point numbers in a different way and offer functions for common arithmetic and mathematical operations that can provide results of accurate precision. If you are curious about the internal data representation of the float data type in elixir, check out this article.