PHP 4.0 Bug #9288 Updated: Math operations give wrong result under certain type-conversion circumstances
| From: | derick@php.net | Date: | Thu, 15 Feb 2001 19:51:28 +0000 |
| Subject: | PHP 4.0 Bug #9288 Updated: Math operations give wrong result under certain type-conversion circumstances | ||
| Groups: | php.dev | ||
| Request: | Send a blank email to php-dev+get-46699@lists.php.net to get a copy of this message | ||
ID: 9288
Updated by: derick
Reported By: tim@timj.co.uk
Old-Status: Open
Status: Bogus
Bug Type: Math related
Assigned To:
Comments:
This is very normal in the world of floating point math. All numbers you write and have a fraction
are only very good approximations of a number.
Previous Comments:
---------------------------------------------------------------------------
[2001-02-15 14:29:53] tim@timj.co.uk
Please, I believe I have found a serious bug. I can reproduce it 100%.
Essentially I have a loop (I think this might be significant?) that checks through some rows in a
database and if the value of a row (an amount of money) is less than the total ($total2pay) then the
ID for that row is inserted into an array to be cancelled, and the total is reduced by the amount of
that row.
The loop works fine, unless there are a number of items which add up exactly to the total. Then,
when subtracting the final item (so we get x - x) instead of 0 we get something like
2.7755575615629E-17.
Below is the problem script and underneath that is the output I get. The script has been expanded
out to use more variables to make it clearer and prints some debugging stuff. It's not
incredibly efficient on SQL requests, but that's irrelevant.
I will gladly give any more information or debug output on request if it's helpful. NB I do
NOT have the Zend Optimiser running for this.
The database structure of table 'debts' is:
id int(10), owed_to varchar(20), owed_by varchar(20), amount decimal (10,2)
// Let there be initially 3 rows in the db which match the query below, // with amount =
"0.71", "0.20" and "0.10" respectively
$res = db_query("SELECT * FROM debts WHERE owed_by='$who_is_paying' AND
owed_to='$payee' ORDER BY amount DESC");
// Let $total2pay = 1.01
do {
while ($row = mysql_fetch_array($res)) {
if ($row[amount] <= $total2pay) { // cancel item
$cancel[] = $row[id];
print "oldtotal:$total2pay,type ".gettype($total2pay)."<br>";
$new = $row[amount];
print "amount2delete:$new, type ".gettype($new)."<br>";
// BELOW LINE IS THE PROBLEM ONE
$fish= $total2pay - $new;// deduct it from the total owed
print "newtotal:$fish,type ".gettype($fish)."<br>";
$total2pay = $fish;
}
}
// delete the marked items from the database
if ($cancel) {
reset($cancel);
while ($item = each($cancel)) {
db_query("DELETE FROM debts WHERE id='$item[value]'");
}
}
// retrieve the fresh, updated item list from the databas
mysql_free_result($res);
$res = db_query("SELECT * FROM debts WHERE owed_by='$who_is_paying' AND
owed_to='$payee' ORDER BY amount DESC");
$rows = db_num_rows($res);
} while (($total2pay > 0) && ($rows > 0) && $cancel);
The output from this is:
oldtotal:1.01,type string
amount2delete:0.71, type string
newtotal:0.3,type double
oldtotal:0.3,type double
amount2delete:0.20, type string
newtotal:0.1,type double
oldtotal:0.1,type double
amount2delete:0.10, type string
newtotal:2.7755575615629E-17,type double
I have played a bit to try to fix it, and found that if I set $new explicitly to type double just
before the problem line, the output is exactly the same, i.e. the output is:
oldtotal:1.01,type double
amount2delete:0.71, type double
newtotal:0.3,type double
oldtotal:0.3,type double
amount2delete:0.2, type double
newtotal:0.1,type double
oldtotal:0.1,type double
amount2delete:0.1, type double
newtotal:2.7755575615629E-17,type double
Another thing: if there is only one row in the database and this adds up to the total, it works
fine:
oldtotal:1.01,type string
amount2delete:1.01, type double
newtotal:0,type double
I really hope someone can help me get to the bottom of this!
---------------------------------------------------------------------------
ATTENTION! Do NOT reply to this email!
To reply, use the web interface found at http://bugs.php.net/?id=9288&edit=2