PHPFixing
  • Privacy Policy
  • TOS
  • Ask Question
  • Contact Us
  • Home
  • PHP
  • Programming
  • SQL Injection
  • Web3.0

Friday, July 22, 2022

[FIXED] Why do I get a different result from two supposedly analogous arithmetic operations?

 July 22, 2022     php, php-5.4     No comments   

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)
  • Share This:  
  •  Facebook
  •  Twitter
  •  Stumble
  •  Digg
Newer Post Older Post Home

0 Comments:

Post a Comment

Note: Only a member of this blog may post a comment.

Total Pageviews

Featured Post

Why Learn PHP Programming

Why Learn PHP Programming A widely-used open source scripting language PHP is one of the most popular programming languages in the world. It...

Subscribe To

Posts
Atom
Posts
Comments
Atom
Comments

Copyright © PHPFixing