Dangerous Dave
Dangerous Dave

Reputation: 21

Php comparison integer with double

I got a problem with this script

 $total = 0;
    $expected_total =  1111;
    $i = [85.46,85.46,85.46,85.46,85.46,85.46,85.46,85.46,85.46,85.46,85.46,85.46,85.48];
    foreach ($i as $item) { $total += $item; }
    if($total != $expected_total) {
        echo json_encode([$total,$expected_total]);
    }

The problem is that at the end of the sum the $total should be equal to the $expected_total. I thought about different number types, I printed the type of the two vars and I was right, one was double and the other was integer, so I converted the integer to double

$expected_total = 1111.00;

but the result is still the same.

The only solution that I could find was comparing the rappresentation of the two numbers, casting them to a string.

 if((string)$total != (string)$expected_total) {
        echo json_encode([$total,$expected_total]);
    }

But obviously this is kind of a hack.

Have you ever had a similar problem? How have you solved it?

PHP version : 5.5.9 Many Thanks

Upvotes: 0

Views: 2359

Answers (3)

UrsaDK
UrsaDK

Reputation: 865

There is a big red label in the PHP Manual, that says:

Floating point numbers have limited precision…

So never trust floating number results to the last digit, and do not compare floating point numbers directly for equality. If higher precision is necessary, the arbitrary precision math functions and gmp functions are available.

In this specific case, you could add the floating numbers using bcadd() and compare the totals using bccomp(). Both functions are provided by the BC Math extension:

foreach ($i as $item) { 
    $total = bcadd((string) $total, (string) $item, 2);
}
if (bccomp((string) $total, (string) $expected_total, 2) == 0) {
    echo json_encode([$total,$expected_total]);
}

Upvotes: 0

Jeroen de Jong
Jeroen de Jong

Reputation: 337

If you want to check them as integers you could round both values. You should change the if-statement to the following:

if(round($total) != round($expected_total)) {
  echo json_encode([$total,$expected_total]);
}

If you do it like this you will compare the rounded values, which will be the same.

Upvotes: 0

Robert
Robert

Reputation: 20286

This is not only PHP problem. It is about representation of floating point numbers in memory. Floating numbers has limited precision. PHP uses IEEE 754. Read carefully the manual page and you will understand.

You can find in manual code snippet of how to do it.

$a = 1.23456789;
$b = 1.23456780;
$epsilon = 0.00001; //very small number

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

Upvotes: 3

Related Questions