There are some very well known problems with floating-point numbers and
arithmetics due to the fact most decimal fractions cannot be represented by a
floating-point binary and most operations are not exact, but operate on
approximations. Those issues are not specific to Elixir, they are a property of
floating point representation itself.
For example, the numbers 0.1 and 0.01 are two of them, what means the result of
squaring 0.1 does not give 0.01 neither the closest representable. Here is what
happens in this case:
• The closest representable number to 0.1 is 0.1000000014
• The closest representable number to 0.01 is 0.0099999997
• Doing 0.1 * 0.1 should return 0.01, but because 0.1 is actually
0.1000000014, the result is 0.010000000000000002, and because this is not
the closest representable number to 0.01, you’ll get the wrong result for
this operation
There are also other known problems like flooring or rounding numbers. See
round/2 and floor/2 for more details about them.
To learn more about floating-point arithmetic visit:
For future folks…I have converted floating-point numbers to strings up to 3 decimal places with the following function: :erlang.float_to_binary(float, [{:decimals, 3}, :compact])
It will provide floating numbers as a string without scientific notation. And helper function as follows:
def float_string(float, decimals) when is_float(float) do
s = :erlang.float_to_binary(float, [{:decimals, decimals}, :compact])
Regex.replace(~r/\.0\z/, s, "")
end
That’s true for single-precision floats, but the beam uses double-precision, so it’s actually:
iex> 0.1 == 0.100000000000000005551
true
(actually even for single-precision floats, apparently the value stored for 0.1 is really 0.100000001490116119384765625)
edit: I pulled that 0.100000000000000005551 value from a @kwando’s function above, but in fact any decimals added after 0.10000000000000001 will produce the same float. I suspect that :io_lib.format doesn’t give us the full accurate decimal representation, probably because the precision is meaningless as any other number nearby would also be represented as the same value.
edit2: According to this the actual value of 0.1 is 0.1000000000000000055511151231257827021181583404541015625.
Also this is a nice quote from the same article (I changed the number to 0.1 for clarity):
So when you print out that number, why does it display 0.1?
The computer isn’t actually printing out the exact value of the number, instead it’s printing out the shortest decimal number d which has the property that our floating point number f is the closest floating point number to d.