1

I'm utterly confused why PHP is behaving the way it is below.

Context: I'm using a third party payment gateway library. For some reason some of my payments are getting charged 1c less! Which is a huge problem for us. To make things even more odd, it only seems to be for some specific amounts

Looking at their code I was able to reproduce this in a simple php script.

<?php
$val = 568.3 * 100;
echo $val;
echo "\n";
echo (float) ($val);
echo "\n";
echo (int) ($val);
echo "\n";
echo intval($val);
echo "\n";
?>

Expected output would be 56830 for all the echo's but instead, when its casting or using intval it prints out 56829 (1c less) and using no type cast or float works. The fix seems to be just not using int or intval conversions but am very curious why this is happening.

If you put in 56830 then it all prints fine. Reproduceable with 568.31 * 100 but not 568.32 * 100.

Can anyone help me understand whats happening?

EDIT: float / floatval / no casting returns the expected value.

The follow works, just when using 568.3 it loses 1 cent! $val = 5.3 * 100; $val = 56888.3 * 100;

  • How about using [`floatval()`](http://ch1.php.net/manual/en/function.floatval.php) ? – samayo Jun 29 '14 at 02:27
  • http://stackoverflow.com/questions/3730019/why-not-use-double-or-float-to-represent-currency/ – zneak Jun 29 '14 at 02:31
  • read here from the php manual http://in3.php.net/language.types.float ...although for conversion to int you can first convert the float result to string and then to int like echo (int) (string) ($val); – rock321987 Jun 29 '14 at 02:47

2 Answers2

1

FuzzyTree's answer explained the problem with floating point arithmetic. You can fix it by using round before intval.

<?php
$val = 568.3 * 100;
echo $val;
echo "\n";
echo (float) ($val);
echo "\n";
echo (int) (round($val));
echo "\n";
echo intval(round($val));
echo "\n";
?>

Output:

56830
56830
56830
56830
merlin2011
  • 71,677
  • 44
  • 195
  • 329
0

$val is float with a value of something like 56829.999999... and it gets rounded down when converting to an int.

From the manual

http://www.php.net/manual/en/language.types.integer.php

From floating point numbers ¶

When converting from float to integer, the number will be rounded towards zero.

If the float is beyond the boundaries of integer (usually +/- 2.15e+9 = 2^31 on 32-bit platforms and +/- 9.22e+18 = 2^63 on 64-bit platforms other than Windows), the result is undefined, since the float doesn't have enough precision to give an exact integer result. No warning, not even a notice will be issued when this happens!

FuzzyTree
  • 32,014
  • 3
  • 54
  • 85
  • But if i have "(int) 56888.3 * 100" it works as expected? its just that when i have "(int) 568.3 * 100" it gives 56829. Additionally "5.3 * 100" gives 5.3... ? – user3786983 Jun 29 '14 at 02:30
  • when you `echo` it rounds to the nearest integer, but when you `cast` from float to int it rounds down – FuzzyTree Jun 29 '14 at 02:31
  • Thanks FuzzyTree, Yeah tried on java as well and can see the output is coming through as ..29.99999 the fix is straight forward with rounding first / not doing any casting but just wanted to know. Thanks! – user3786983 Jun 29 '14 at 02:42