# Integer precision issue

Go to solution Solved by requinix,

## Recommended Posts

So I have this very simple integer/float conversion method to convert basically a money value like 573.06 to cents.  The 573.06 would come in as a string from a submitted form value.  I would run it through the following code and it was coming out the wrong value as 57305 not 57306 as expected.

```function convertToMoneyInteger(\$input)
{
return (int)(\$input * 100);
}```

After some fiddling, I found a way to make it work but I'm not sure it's the best or most accurate way even after running multiple tests on random values. This is the new method that seems to work.

```function convertToMoneyInteger(\$input)
{
return (int)(string)(\$input * 100);
}```

All I did was convert it back to a string before ultimately converting back to an integer.  It just feels wrong or incorrect.

I have an automated test that runs 106 assertions against the result of the convertToMoneyInteger method and it always comes back green.

```public function returns_correct_integer_for_convertToMoneyInteger_function()
{
\$input = '573.06';
\$this->assertEquals(57306, convertToMoneyInteger(\$input));

\$input = '573.05';
\$this->assertEquals(57305, convertToMoneyInteger(\$input));

\$input = '573.07';
\$this->assertEquals(57307, convertToMoneyInteger(\$input));

\$input = '22.91';
\$this->assertEquals(2291, convertToMoneyInteger(\$input));

\$input = '34.54';
\$this->assertEquals(3454, convertToMoneyInteger(\$input));

\$input = '50.00';
\$this->assertEquals(5000, convertToMoneyInteger(\$input));

for (\$x = 0; \$x <= 100; \$x++){
\$value = \$this->rand_float(20, 600);
\$result = (string)(\$value * 100); // Only convert to string so it's not identical to the convert function as it would be pointless because it would always return true.
\$this->assertEquals(\$result, convertToMoneyInteger(\$value));
}
}

function rand_float(\$st_num=0,\$end_num=1,\$mul=100)
{
if (\$st_num>\$end_num) return false;
return mt_rand(\$st_num*\$mul,\$end_num*\$mul)/\$mul;
}```

Is this accurate enough or is there a better way?

##### Share on other sites

• Solution

That's floating-point arithmetic: the computer can't calculate 573.06 * 100 exactly so it comes up with something close. Something like 57305.9999999999986. And if you truncate that, like with an int cast, then you'll just get 57305. In other cases it might come up with 57306.00000000000005.

The solution is super simple: round the number instead of truncating it.

```function convertToMoneyInteger(\$input)
{
return round(\$input * 100);
}```

Be careful that your \$input is never going to have fractional cents or you'll lose them by rounding to 0 digits. If you're concerned that might be possible, round to an appropriate number of decimal places.

##### Share on other sites

instead of doing math, just explode the string on the '.' character, fill the cents part to two places with trailing '0' characters, and concatenate the two pieces together.

##### Share on other sites

1 hour ago, requinix said:

That's floating-point arithmetic: the computer can't calculate 573.06 * 100 exactly so it comes up with something close. Something like 57305.9999999999986. And if you truncate that, like with an int cast, then you'll just get 57305. In other cases it might come up with 57306.00000000000005.

The solution is super simple: round the number instead of truncating it.

```function convertToMoneyInteger(\$input)
{
return round(\$input * 100);
}```

Be careful that your \$input is never going to have fractional cents or you'll lose them by rounding to 0 digits. If you're concerned that might be possible, round to an appropriate number of decimal places.

Is there a php method I can use in the future to see that decimal precision so I can understand more quickly why it's not doing what I want?

##### Share on other sites

I won't ever use anything except standard US currency and it will always only be 2 decimal points in cents, so if that means I don't have to worry about "fractional cents" then great.  Otherwise please explain more as to what you mean by that term.

##### Share on other sites

you can also use the BC math functions, which expects strings as input and operates on each character as a bcd digit, like a hand held calculator works.

##### Share on other sites

Using number_format() allowed me to see the precision of decimals but I had to go out to 11+ decimals or it would only show zeros.  Once I hit the 11 decimal all the sudden it showed multiple 9's and other numbers.  So weird how that crap works.

##### Share on other sites

There are some ini settings that control how PHP rounds the precision of floating point numbers.  There is a higher precision for serialization, so a quick and dirty way of seeing the "raw" numbers would be to serialize it.

`echo serialize('573.06'*100);`

shows

`d:57305.99999999999;`

## Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

×   Pasted as rich text.   Restore formatting

Only 75 emoji are allowed.