0

I am using PHP 5.5 (5.5.28) I have come across a really weird problem with PHP arithmetic

$value=29; $divisor=10;
$mod=$value%$divisor;
echo "$mod<br>";

returns 9 (as expected)

$value=(0.29*100); $divisor=(0.1*100);
$mod=$value%$divisor;
echo "$mod<br>";

returns 8 (????)

I can't find anything about this in the documentation Obviously its relatively easy to write a replacement function and use that However, the problem seems to be bigger, in that I am getting weird rounding errors which mean my ledger entries in the project I am working on are not balancing

Any suggestions?

5
  • 6
    Read, learn and inwardly digest, and read the big warning message on this PHP Docs page.... if you're writing a ledger, you should never truust the precision of floats in any programming language, always using integer Commented Sep 12, 2016 at 7:13
  • Thanks Mark ... naive of me to assume that common sense would apply Commented Sep 12, 2016 at 7:28
  • 2
    Common Sense? There's a reason infinitely large decimal values can't be stored in a fixed number of binary bytes, and you are duly presented with a large warning when you visit the page concerned! Commented Sep 12, 2016 at 7:35
  • 1
    Common sense would be to use the right type of opernand for the operator you are using and % expects integers. According to the manual: Operands of modulus are converted to integers (by stripping the decimal part) before processing.. You could of course also use fmod() - that actually returns 9 in your test case - but as @MarkBaker already mentioned, you should never trust the precision of floats when working with ledgers. Commented Sep 12, 2016 at 7:42
  • This isn't anything to do with common sense.... it's common across almost every programming language; and exactly the same problem exists when human beings use decimal, there are numbers such as 1/3 that cannot be represented in decimal, so we always work with "estimates" Commented Sep 12, 2016 at 8:06

1 Answer 1

2

This is almost-certainly related to the way that floating point numbers are stored and you have the issue where .29*100 is not EXACTLY equal to 29 and 0.1*100 is not EXACTLY equal to 10. Hence if one is slightly smaller or larger than you expected then you get a result that is out by one. If you print your intermediate values out with 10 decimal place you will probably be able to observe the cause

This is exactly the same issue you have when trying to compare equality of floats and you end up having to do something like: if(fabs(a-b) < 0.0001) rather than saying: if(a==b)

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.