php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #61108 string math with vast differential numbers yield invalid math.
Submitted: 2012-02-16 17:18 UTC Modified: 2012-02-16 18:18 UTC
From: qphoria at gmail dot com Assigned:
Status: Not a bug Package: Math related
PHP Version: 5.3.10 OS: Windows/Linux
Private report: No CVE-ID: None
View Add Comment Developer Edit
Welcome! If you don't have a Git account, you can't do anything here.
You can add a comment by following this link or if you reported this bug, you can edit this bug over here.
(description)
Block user comment
Status: Assign to:
Package:
Bug Type:
Summary:
From: qphoria at gmail dot com
New email:
PHP Version: OS:

 

 [2012-02-16 17:18 UTC] qphoria at gmail dot com
Description:
------------
Tried this on the latest 5.3.10 and also on 5.2.17
It is a bit difficult to put into words, but math with varying string-number 
sizes calculates wrong.

Simply put:

THIS IS CORRECT:
-----------------
$x = 20.22
: double = 20.22
$y = ("10.10" + "10.12");
: double = 20.22
$x == $y
: bool = TRUE


THIS IS BUGGED:
-------------------
$x = 20.22
: double = 20.22
$y = ("19.10" + "1.12"); //20.22
: double = 20.22
$x == $y
: bool = FALSE

For some reason, if you have a wide number spread in the string math, the 
boolean fails, even though they are both shown as float/double numbers

The simple fix is to wrap round() around the string math. Can't really explain 
it.

Test script:
---------------
<?php
$x = 23.36;
$y = ("21.42" + "1.94");
if ($x < $y) {
	echo "math fail<br/>";
} else {
	echo "math win<br/>";
}
var_dump($x, $y);
echo "<br/>";

$x = 23.36;
$y = ("10.36" + "13.00");
if ($x < $y) {
	echo "math fail<br/>";
} else {
	echo "math win<br/>";
}
var_dump($x, $y);
?>


Expected result:
----------------
I expect to see:

math win
float(23.36) float(23.36) 
math win
float(23.36) float(23.36)

Actual result:
--------------
What I really see is:

math fail
float(23.36) float(23.36) 
math win
float(23.36) float(23.36)

Patches

Add a Patch

Pull Requests

Add a Pull Request

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2012-02-16 17:24 UTC] rasmus@php.net
-Status: Open +Status: Not a bug
 [2012-02-16 17:24 UTC] rasmus@php.net
Floating point values have a limited precision. Hence a value might 
not have the same string representation after any processing. That also
includes writing a floating point value in your script and directly 
printing it without any mathematical operations.

If you would like to know more about "floats" and what IEEE
754 is, read this:
http://www.floating-point-gui.de/

Thank you for your interest in PHP.

.
 [2012-02-16 17:50 UTC] qphoria at gmail dot com
Perhaps, but then why wouldn't the additional decimals show in the variable?
The initial string math should have returned:
20.22000003
if that was the case.

I would expect to see:

$x = 20.22
: double = 20.22
$y = ("10.10" + "10.12");
: double = 20.22000030
or
20.22e08 or something
 [2012-02-16 18:00 UTC] qphoria at gmail dot com
It seems the proposed solution is that we should always add
round($y,2)
to any string math. But if php is going to return exact numbers to the variable 
dump, but hide the "real" value in the back end.. then what is the point? The 
bug may not be with floating, but instead with the way php outputs the variable. 
If we are meant to always round string math, then you may as well add the 
round() function to the last step of the string math result in the php exe and 
spare the rest of us. Nobody can trust (float) now because what php outputs 
isn't really what it uses to calculate. Unless there is some way to find out 
that hidden "epsilon" value.
 [2012-02-16 18:05 UTC] qphoria at gmail dot com
I guess this would be a more relevant read:
http://www.cygnus-software.com/papers/comparingfloats/comparingfloats.htm

Seems to clear it up more.
 [2012-02-16 18:18 UTC] rasmus@php.net
If you change your output precision setting you will see it. But that is just for 
final output purposes. If we rounded every float internally you would lose a lot 
of precision since all these would pile up and cause actual math errors. But yes, 
it does mean you have to be careful if you are trying to do strict equivalence 
checking on floats. But that is the same for most languages that use the 
underlying float implementation. There are higher-level ones, of course, but they 
are quite a bit slower.
 
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Mon Jun 17 03:01:28 2024 UTC