0

I'm getting fmod returning wrong result, am i doing anything wrong?

for($i = 0.00; $i < 1; $i = $i + 0.05) {
    var_dump($i." = ".fmod($i, 0.05));
}

Output:

0.= 0
0.05 = 0
0.1 = 0
0.15 = 1.3877787807814E-17
0.2 = 0
0.25 = 0.05
0.3 = 0.05
0.35 = 0.05
0.4 = 0.05
0.45 = 0.05
0.5 = 0.05
0.55 = 0.05
0.6 = 0.05
0.65 = 0.05
0.7 = 2.7755575615629E-17
0.75 = 6.9388939039072E-17
0.8 = 1.1102230246252E-16
0.85 = 1.5265566588596E-16
0.9 = 1.942890293094E-16
0.95 = 2.3592239273285E-16

I was expecting every result to be the same: 0.

Sheraf
  • 493
  • 5
  • 9

2 Answers2

1

First, fmod is exact. Because it can: when x and y are floating-point numbers, the mathematical result of fmod(x,y) can be represented exactly as a floating-point number.

Second, when you write 0.05, you do not get exactly that number, because 5/100 on the other hand cannot be represented exactly as a floating-point number; and when you write +, you do not get mathematical addition in general because the result of that mathematical addition cannot always be represented as a floating-point number(*).

Starting from 0.0 and repeatedly adding 0.05 will soon get you into inaccurate + territory, because in binary, the best representation of 0.05 has many digits. As the sum gets larger, the last digits progressively have to be dropped. This is where the inaccuracy of + comes from, and ultimately is the reason why fmod does not give you the results you expect.

It wouldn't matter that 0.05 is not exactly 5/100 if repeatedly adding it to zero always was exact. But since the floating-point number 0.05 has many digits in binary (as opposed to decimal) and since some of these digits must be lost when computing multiples of 0.05, the value you get for most multiples y of 0.05 when computing fmod(y, 0.05) is not zero but represents the difference between the mathematical multiplication of the appropriate integer by 0.05 and the approximation y of that number.

(*) when the mathematical sum can be represented, the mathematical sum is what you get, but sometimes it just cannot.

Pascal Cuoq
  • 79,187
  • 7
  • 161
  • 281
0

This answer relates to the first revision of the question:

https://stackoverflow.com/revisions/28372286/1

All is working fine! You can calculate it for yourself:

fmod(0.5, 0.25);
fmod(0.5, 0.23);
fmod(0.5, 0.20);

0.25 * 2 = 0.50   | Rest 0.00
0.23 * 2 = 0.46   | Rest 0.04
0.20 * 2 = 0.40   | Rest 0.10
Community
  • 1
  • 1
Rizier123
  • 58,877
  • 16
  • 101
  • 156