Issue
In the following code, why is the multiplication approach not producing rounding errors, while the cumulative addition approach is?
function get_value() { return 26.82; }
function a($quantity) {
$value_excluding_vat = get_value();
$value_including_vat = round($value_excluding_vat * (1 + (20 / 100)),2);
$total_nett = 0;
$total_gross = 0;
for($i=0; $i<$quantity; $i++) {
$total_nett += $value_excluding_vat;
$total_gross += $value_including_vat;
}
return array(
$total_nett,
$total_gross
);
}
function b($quantity) {
$value_excluding_vat = get_value();
$value_including_vat = round($value_excluding_vat * (1 + (20 / 100)),2);
return array(
$quantity * $value_excluding_vat,
$quantity * $value_including_vat
);
}
$totals = a(1000);
print_r($totals);
echo $totals[1] - $totals[0];
echo "\n\n";
$totals = b(1000);
print_r($totals);
echo $totals[1] - $totals[0];
Here's my output:
Array
(
[0] => 26820
[1] => 32180
)
5360.0000000005
Array
(
[0] => 26820
[1] => 32180
)
5360
Solution
Firstly, consider that there are many numbers which are rational in base 10, but not in a binary floating point representation. For example, the floating point value of 26.82 is actually 26.8200000000000002842170943040400743484497
Naturally, if you keep adding this to itself some errors creep in, but up to 15 significant digits you should be fine - add this 1000 times and the sum is actually 26819.9999999997671693563461303710937500000000
The interesting question though is when we multiple 26.82 by 1000.0 we get 26820.0000000000000000000000000000000000000000
- how does it do that?
The answer there is simply that 26820.0 does have an exact binary representation, and the multiplication operation is smart enough to spot that - even multiplying by 1001.0 and subtracting 26.82 would still get you an exact answer.
Here's a few interesting links
- http://www.h-schmidt.net/FloatConverter/ - this lets you look at single-precision representation of floating point numbers, and can be useful in really understanding floats
- This RFC on PHP rounding is tangentially interesting as it covers some of the issues around rounding floats
- and What Every Computer Scientist Should Know About Floating-Point Arithmetic
Answered By - Paul Dixon Answer Checked By - David Marino (PHPFixing Volunteer)
0 Comments:
Post a Comment
Note: Only a member of this blog may post a comment.