This is due to the conversion of real numbers into decimal to floating-point numbers on a binary basis (according to IEEE 754). In general, this happens when the number is not a sum of exponents of 2.
It should be understood that floats are represented in binary form, typically with 32 or 64 bits:
- Signal bit (0 - positive, 1 - negative)
- Exponent (8 or 11 bits)
- Mantissa or fractional part (23 or 52 bits)
Where the formula is:
Base 2: (-1)sign 10exponent - (1111111 or 1111111111) 1 mantissa
Exceptions:
+0 and -0 have exponent = 0 and mantissa = 0
+Inf and -Inf have exponent = all 1s and mantissa = 0
Nans have exponent everything 1s and mantissa different from 0
These utilities ([1], [2]) help to understand the representation of 0.10 and 0.05 in single floats (32 bits). Experiment with 4.0, 2.0, (positive exponents of 2) 1.0 (exponent 0, coded as 127), 0.5, 0.25, 0.125, (negative exponents of 2), 0.375 (sum of 0.125 three times) and then with 0.1, 0.01, 0.3, etc..
For example, with the second utility, click on "Add An Analyzer". Select "decimal" on the left and enter 0.1. Select "Binary" on the right and enter 0.00011001100110011001101.
In this case, we observe a rounding:
0,110
= 0,000 1100 1100 1100 1100 1100 1100...2
0,000 1100 1100 1100 1100 11012 (rounding)
= Base 2: (-1)0 10111 1011 - 111 1111 1,100 1100 1100 1100 1101
The way to convert this number back to decimal basis is similar to integers, only each bit after the comma is multiplied with a negative exponent of 2:
Σi bi 2i, i PRA : min i max
In this case, min = -27, max = 0
0 20 + 0 2-1 + 0 2-2 + 0 2-3
+ 1 2-4 + 1 2-5 + 0 2-6 + 0 2-7
+ 1 2-8 + 1 2-9 + 0 2-10 + 0 2-11
+ 1 2-12 + 1 2-13 + 0 2-14 + 0 2-15
+ 1 2-16 + 1 2-17 + 0 2-18 + 0 2-19
+ 1 2-20 + 1 2-21 + 0 2-22 + 0 2-23
+ 1 2-24 + 1 2-25 + 0 2-26 + 1 2-27
= 0,100000001490116119384765625
0,1 (rounding off)
Even if there were no rounding in the input data, it does not mean that the results cannot be different than expected. For example, sums and subtractions suffer much more from the exponent difference than multiplications and divisions.
Often, what we see as an equality comparison (x = 2.5) in mathematical terms has to be an interval comparison in terms of floating comma (2.5 - ε x 2.5 + ε).
This ε (epsilon) should be a value in the scale of the value we are checking.
It doesn’t make sense that the difference is the smallest floating possible, because if you do, you’ll notice that 2.5 smallest floating possible ≈ 2,5. That is, the sum of fact is as if it did not happen, because the values are very far away on the scale. Precision is finite, as you would expect.
On the other hand, it’s also not very good to use the float immediately below or above (unless we want to even such accuracy), but perhaps the second, third, I don’t know, tenth float below or above.
In practical terms, it should be a function to do this work, if not a macro for when the comparison term is constant. This is because it is not common for programming languages to have syntax for binary floats, such as 10.12 (2,510), the more such a single-float 10,1000000000000001002 (8º single-floats above 2,5) or 10,01111111111110002 (8º single-float below 2.5). Or even if the language even has syntax, it is nothing readable or practical.
It’s the same if you use
(0.1+0.05) == 0.15
?– Tiago César Oliveira
For the same reason described in that question
– Math
Dear friends, in order not to appear that the question is repeated, I will restrict the scope of the question to solutions only in the
R
. Note that the other question does not provide solutions to theR
- packages, functions etc.– Carlos Cinelli