Let's understand why you get 60054
.
<?php
$value = 600.55 * 100;
printf('%.18f', $value);
The output is: 60054.999999999992724042
.
$value
is a floating-point number. Its value might not be represented in memory as you expect. It's an approximation. That's why, for instance, it's a very bad idea to use floating-point numbers for money. Probably it's fine for geographic coordinates.
Why $value = str_replace('.', '', 600.55);
seems to work properly?
<?php
echo 600.55;
The output is: 600.55
.
<?php
printf('%.18f', 600.55);
The output is: 600.549999999999954525
.
<?php
$value = 600.55;
printf('%s => %.18f', $value, str_replace('.', '', $value));
The output is: 600.55 => 60055.000000000000000000
.
<?php
echo str_replace('.', '', 600.5599999999999);
The output is: 60056
.
When a floating-point is cast to a string, the string doesn't have all decimal digits. You'll get an “educated guess”. In your case, 600.55
was implicitly cast to "600.55"
because the arguments of the function str_replace
are expected to be strings.
So what should you do?
If you only want to multiply a number by 100, it seems rounding works fine:
<?php
$value = (int)round(123.45 * 100);
var_dump($value);
The output is: int(12345)
.
Note: I read a comment saying round(600.123 * 100);
gives 600122
instead of 600123
. That happens because 600.123 has more than two decimal digits, and the last one is lesser than 5.
But if you're performing lots of operations, it might fail:
$value = 0;
for ($i = 0; $i < 50; ++$i) {
$value += .2;
}
var_dump((int)$value, .2 * 50);
The output is: int(9) float(10)
.
There's a mathematical extension, BCMath, to handle operations with decimal numbers that require precision. It uses strings to represent numbers:
<?php
$value = bcmul('600.55', '100');
var_dump($value);
The output is: string(5) "60055"
.
If performance is a priority, you may also implement a way to represent fixed point numbers. Or splitting the integer and decimal sides:
<?php
$integer = 600;
$decimal = 55;
$value = $integer * 100 + $decimal;
The output is: int(60055)
.