You may think that 1/10 is quite a precise number, I mean it’s 0.1 isn’t it? Easy to convert, one-tenth right? Wrong. Only some numbers, e.g. those with a denominator containing a factor of 5, can be precisely represented. All others are imprecise. So this is understandable for numbers such as ￼, because the answer to this is 0.3333333…. recurring infinitum. The more 3’s you add to the end, the more accurate the approximation becomes. But it is still an approximation. Less easy to see with ￼, because the answer here is 0.1. The problem lies, NOT with the numbers themselves, but in the conversion to binary. Yes, all numbers have to be converted to binary in the inner workings of the CPU because that’s how they are processed.
Unfortunately, most decimal fractions cannot be represented exactly as binary fractions. A consequence is that, in general, the decimal floating-point numbers we enter are only approximated by the binary floating-point numbers actually stored in the machine. Now 1/10 cannot be represented accurately because no matter how many base 2 digits you’re willing to use, the decimal value 0.1 cannot be represented exactly as a base 2 fraction. In base 2, 1/10 is the infinitely repeating fraction:
You can see a repeating base of 1001. Stop at any finite number of bits, and you get an approximation. This is why we see things like:
0.10000000000000001 or 0.0999999999999998
The consequence of this is that summing ten values of 0.1, may not exactly yield 1.0. Consider the following example in Fortran (using double precision reals):
program one_tenth implicit none integer, parameter :: dp = selected_real_kind(15, 307) real (kind=dp) :: frac, sum integer :: i frac = 1.0_dp / 10.0_dp print *, frac do i = 1,10 sum = sum + frac end do print *, sum end program one_tenth
Now here is the output produced:
Case in point.