Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Floating point rounding error php ...how can I make sure it works correctly?

Tags:

php

I have the following function that determines if I sale is fully paid for. I don't remember why I did it this way, but it has been working so far and I don't remember why I had to do it this way.

function _payments_cover_total()
{
    //get_payments is a list of payment amounts such as:
    //10.20, 10.21, or even 10.1010101101 (10 decimals max) 

    $total_payments = 0;

    foreach($this->sale_lib->get_payments() as $payment)
    {
        $total_payments += $payment['payment_amount'];
    }

    //to_currency_no_money rounds total to 2 decimal places
    if (to_currency_no_money($this->sale_lib->get_total()) - $total_payments ) > 1e-6 ) )
    {
        return false;
    }

    return true;
}

I am wondering if there is ever a case where due to a rounding error that this function would return false when it shouldn't.

The main part I have a question about is:

 > 1e-6

I think before I had, but it was causing problems in some cases.

> 0
like image 861
Chris Muench Avatar asked Apr 23 '14 21:04

Chris Muench


People also ask

How do you solve rounding errors?

Rounding half to even also known as banker's rounding - if the truncated fraction is greater than half the base, increase the last remaining digit. If it is equal to half the base, increase the digit only if that produces an even result. This minimizes errors and bias, and is therefore preferred for bookkeeping.

Can floating point operations cause round off errors?

Roundoff error caused by floating-point arithmetic Even if some numbers can be represented exactly by floating-point numbers and such numbers are called machine numbers, performing floating-point arithmetic may lead to roundoff error in the final result.

Why do floating point rounding errors occur?

It's a problem caused when the internal representation of floating-point numbers, which uses a fixed number of binary digits to represent a decimal number. It is difficult to represent some decimal number in binary, so in many cases, it leads to small roundoff errors.

How do you round a floating-point number?

The round() function returns a floating point number that is a rounded version of the specified number, with the specified number of decimals. The default number of decimals is 0, meaning that the function will return the nearest integer.


1 Answers

I think you are doing what is mentioned on php floating help page. To quote it directly :

To test floating point values for equality, an upper bound on the relative error due to rounding is used. This value is known as the machine epsilon, or unit roundoff, and is the smallest acceptable difference in calculations.

$a and $b are equal to 5 digits of precision.

<?php
$a = 1.23456789;
$b = 1.23456780;
$epsilon = 0.00001;

if(abs($a-$b) < $epsilon) {
    echo "true";
}
?>

So in your case:

(to_currency_no_money($this->sale_lib->get_total()) - $total_payments) > 1e-6

relative error due to rounding should not be great than 1e-6 or 0.000001

if you are not sure about left operand being greater than right 100% time,then you should add abs() e.g for correctness.

$relative_error=to_currency_no_money($this->sale_lib->get_total()) - $total_payments;
 if(abs($relative_error) > 1e-6){
   return false
 }
 return true;
like image 108
sakhunzai Avatar answered Sep 28 '22 07:09

sakhunzai