Home > Software engineering >  What is the best way to convert a decimal (float) to an integer?
What is the best way to convert a decimal (float) to an integer?

Time:07-31

I was trying to multiply floats containing decimals and was getting incorrect results.

For example, the following code does not calculate correctly....

$value = (int) (600.55 * 100);
var_dump($value); // outputs the number 60054 when it should be 60055

I was able to solve the issue by removing the decimal with str_replace...

$value = str_replace('.', '', 600.55);
var_dump($value); // now outputs the correct number 60055

But I was wondering if there is a more proper way to convert a decimal (float) to an integer so I can do basic math operations without having the numbers change

CodePudding user response:

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).

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, splitting the integer and decimal sides:

<?php
$integer = 600;
$decimal = 55;
$value = $integer * 100   $decimal;

The output is: int(60055).

  •  Tags:  
  • php
  • Related