Why modulus calculation of 2.4 by 0.8 returns 0.8? Shouldn't it return 0?
It happens both in PHP, via fmod
, and JavaScript, via %
.
Even a google research with this operation fails: http://www.google.com/search?q=2.4+mod+0.8
Why modulus calculation of 2.4 by 0.8 returns 0.8? Shouldn't it return 0?
It happens both in PHP, via fmod
, and JavaScript, via %
.
Even a google research with this operation fails: http://www.google.com/search?q=2.4+mod+0.8
Simply put, in order to represent a number in decimal we do something like this:
1550 = 1000 + 5·100 + 5·10 = 1·10³ + 5·10² + 5·10¹
In order to represent a number in binary form from decimal you have to change bases:
106 = 2^6 + 2^5 + 2^3 + 2^1 = 0110 1010
Where 0's would equal to 0·2^7, 0·2^4, etc.
As you can see the pattern is clear: just sum powers of 2 as needed until you get the number you want until you reach 0 (2^0) for the number 1. If you take things a bit further it works the same for decimals, you just keep substracting 1 from the powers:
0.5 = 2^-1 = 1/2^1
Now for other numbers:
0.6875 = 0.1011 = 1/2^1 + 1/2^3 + 1/2^4
However, there are numbers that you can't represent as sums of inverse powers of two, something as simple as 0.1
should require you to add very small numbers to approach that value and would look like 0.0001100110011...
which actually rounds up to 0.0999755859375...
, and since the language has to change bases everytime you have to do arithmetics, these problems start to show up.
If you look closer at what happens in this concrete example, the influence of the binary format becomes more visible.
The input is stored as a binary floating point approximation. This then can be printed as decimal number uniquely identifying the binary,
In [1]: print "%.25f"%2.4
2.3999999999999999111821580
In [2]: print "%.25f"%0.8
0.8000000000000000444089210
The first step is the computation of the quotient and of its integer part. Obviously, as the stored numbers are smaller 2.4
and larger 0.8
, the quotient is smaller than 3
,
In [3]: print "%.25f"%(2.4/0.8)
2.9999999999999995559107901
The modulo result, the remainder, is then finally the difference after removing the integer multiple,
In [4]: print "%.25f"%(2.4-2*0.8)
0.7999999999999998223643161