17

I have two variables, $_REQUEST['amount'] and $carttotal, on an e-commerce thing. They of course should match when attempting to process a payment, so as to prevent a manual override of the payment amount at the last minute, or of course, a calculation error.

However:

$carttotal = $carttotal * 1;
$_REQUEST['amount'] = $_REQUEST['amount'] * 1;

if($carttotal != $_REQUEST['amount']) {
    $code = 0; // cart empty under this user - cannot process payment!!! 
    $message = 'The cart total of ' . $carttotal . ' does not match ' . $_REQUEST['amount'] . '. Cannot process payment.';
    $amount = $carttotal;
    $json = array('code' => $code,
                  'message' => $message,
                  'amount' => $amount);
    die(json_encode($json));
} else {
    $trnOrderNumber = $client->id . '-' . $carttotal;
}

The above code, with the same numbers passed, is NOT giving me the equal. Basically I get the error message as if the $carttotal != $_REQUEST['amount'] is true (unequal vars).

So to test the vars, I snuck in:

var_dump($_REQUEST['amount']);
var_dump($carttotal);

To see what is going on (after I do the * 1 calculations to make sure they are dealt with as floats, not strings).

I got this back:

float(168.57)
float(168.57)

Very very frustrating. What could be causing this?

Cody Gray - on strike
  • 239,200
  • 50
  • 490
  • 574
jeffkee
  • 5,106
  • 12
  • 44
  • 76
  • in PHP, if you are using the != instead of !== the variable type should not matter as it will normalize the variable types when doing the comparison. – dqhendricks Dec 03 '11 at 00:03
  • dqhendricks - ya that's what I figured. With a != rather than !== I thought it wouldn't be too strict. The number of decimals match etc. $carttotal is calculated by iterating through rows of products & taxes & quantity, so I expected the float to have some oddities with the decimal points. however it is forced to 2 decimals, as is the amount, so I figured it may work with a simple != comparison but I guess not. – jeffkee Dec 03 '11 at 00:08
  • http://stackoverflow.com/questions/328475/should-we-compare-floating-point-numbers-for-equality-against-a-relative-error , http://stackoverflow.com/questions/4915462/how-should-i-do-floating-point-comparison –  Dec 03 '11 at 00:55
  • 1
    Sorry @jeffkee, that was a bit condescending, I'm sorry. It's just "why don't my floating point numbers equate" is probably the most commonly asked duplicate question here. – Joe Dec 04 '11 at 12:32
  • 1
    It's a commonly asked question because it defies common logic, and the perception that computer calculations are precise to every digit possible - that is the "human" perception of numbers & computer logics. Now we have another page that will be crawled on Google with more related keywords, so that there's a higher chance somebody else will find it without having to post. P.S. I did know a bit about this - however I thought that when I do a vardump() it would still show the infinite number of decimals such as 168.5699999991233521 so that was the really confusing part. – jeffkee Dec 07 '11 at 19:50
  • 1
    It's actually a problem with var_dump and printing floats. – jgmjgm Nov 17 '15 at 21:40

3 Answers3

16

floating point numbers have limited precision. view the warning about comparing them here:

http://php.net/manual/en/language.types.float.php

dqhendricks
  • 19,030
  • 11
  • 50
  • 83
  • 1
    For anyone looking, try [bcmath](https://stackoverflow.com/a/14052953/134824). You may need to install [bcmath extension](http://php.net/manual/en/book.bc.php) in your apache. – evilReiko Aug 30 '17 at 07:33
6

Floating point numbers are NOT 100% accurate! You calculation in PHP may return 10.00000000001 which is NOT equal to 10.

Use sprintf ( http://php.net/manual/en/function.sprintf.php ) to format the floats before you compare them.

Oliver A.
  • 2,870
  • 2
  • 19
  • 21
0

Instead of multiplying by one use number_format.

 $carttotal = number_format((int)$carttotal,2,'.','');
 $_REQUEST['amount'] = number_format((int)$_REQUEST['amount'],2,'.','');
AR.
  • 1,935
  • 1
  • 11
  • 14
  • The number_format will make a string from the number, from my opinion it's not recommended this operation – BCsongor Feb 23 '15 at 08:34
  • 3
    Also, you are casting the amount to an integer, so any numbers after the decimal are now disregarded. `11.20` would equal `11.99` – Jo. Feb 04 '16 at 16:31