Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Surprising float-int conversion in PHP

After spending an hour trying to find out why a PHP script gave me incorrect output, it turned out that a loop ran one iteration short in one particular case.
To explain what is going on: a version number (2-digits, e.g. 1.5 or 2.0) is read from an XML-attribute and is multiplied by 100. The script later iterates over a defined range of version number multiples.

It turns out that 410 == 409, which gives a funny surprise if you compare a counter that increments in steps of 10 against that value.

Which brings me to my question: Am I fundamentally understanding something wrong? Certainly, 4.1, 100, and 410 should all be well-representable as float and should be well-convertible to int without rounding errors?

However, on my system (with PHP 5.3.2 CLI, Zend Engine 2.3.0), the following test case

<?
$a = 100 * 4.1;
$b = (string) $a;
$c = (int) $a;
$d = (int)(string) $a;

var_dump($a);
var_dump($b);
var_dump($c);
var_dump($d);
?>

outputs:

float(410)
string(3) "410"
int(409)
int(410)

I am now doing a (int)(string) conversion which works, but this is kind of a nasty hack that isn't pretty and doesn't quite feel right.
Is there a better (correct, no-hack) solution to get a precise result?

like image 837
Damon Avatar asked May 02 '26 16:05

Damon


2 Answers

You usually can not see, if a value is well-convertible into a float just by looking at it. Read The warning in the manual for an example.

like image 56
KingCrunch Avatar answered May 05 '26 07:05

KingCrunch


Your problem is in the first line:

$a = 100 * 4.1;

The float literal 4.1 does not, in fact, have the value 4.1, and so the result of multiplying it with 100 is not 410 but a little less. Apparently, casting to string rounds up, but casting to int rounds down.

To get the decimal math you expect, use the BC Math functions.

like image 40
Michael Borgwardt Avatar answered May 05 '26 07:05

Michael Borgwardt