Search code examples
phpmathadditionsubtraction

Simple addition and subtraction not working correctly


I've inherited a project written in PHP which has a double entry style cashbook, which requires that the amount going in is equal to the amount going out.

When validating figures entered via a form (to work out if it equals zero), it runs the code below which works fine until there is a decimal number, which seems to make it randomly fall over and return an incorrect value.

In the example below, it returns a really tiny number from 53.87 - 53.87, which should be zero.This has been stripped back to eliminate other things from causing problems, so I've removed a lot of input validation etc.

<?php $inputs = array(
    array(
        "in" => '',
        "out" => '249.6',
    ),
    array(
        "in" => '',
        "out" => '396',
    ),
    array(
        "in" => '554.4',
        "out" => ''
    ),
    array(
        "in" => '145.07',
        "out" => ''
    ),
    array(
        "in" => '',
        "out" => '53.87',
    ),
);
$fTotal = 0;
echo "Start at 0:   ";
foreach($inputs as $key=>$sRef) {
    $itemValid = true;
    $aItem = array();
    $amountIn = $inputs[$key]['in'];
    $amountOut = $inputs[$key]['out'];
    if ($itemValid) {
        echo "'".$fTotal."'";
        $is_in = 0;
        if ($amountIn > 0.0) {
            $is_in = 1;
            echo "+";
            $amount = $amountIn;
            $fTotal = $fTotal + $amountIn;
        } else {
            $is_in = 0;
            echo "-";
            $amount = $amountOut;
            $fTotal = $fTotal - $amountOut;
        }
        echo "'".$amount."'=";
        echo "'".$fTotal."'   |   ";
        $aItem["is_in"] = $is_in;
        $aItem["amount"] = $amount;
        $aItems[] = $aItem;
    }
 }

You can run this on a sandbox here.

Here is the expected output:

Start at 0: '0'-'249.6'='-249.6' | '-249.6'-'396'='-645.6' | '-645.6'+'554.4'='-91.2' | '-91.2'+'145.07'='53.87' | '53.87'-'53.87'='0' |

Here is the actual output:

Start at 0: '0'-'249.6'='-249.6' | '-249.6'-'396'='-645.6' | '-645.6'+'554.4'='-91.2' | '-91.2'+'145.07'='53.87' | '53.87'-'53.87'='-4.9737991503207E-14' |

What is wrong here?

Update

Following help below, here's the working code for anyone who stumbles on this in the future.


Solution

  • This is happening because of floating point (decimal) maths where computers like binary maths. Sometimes decimal numbers don't have a nice representation in binary so these tiny differences happen.

    If you can state that every number can be rounded to 2 decimal points, and based on your limited dataset, wrapping your 'sums' in number_format($fTotal + $amountIn , 2) etc can sort this out for you.

    Alternatively for a "more accurate", just wrap the final one eg. echo "'".number_format($fTotal, 2)."' | "; (or 0 or whatever)