php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #51518 should add to zero, but gets 1.1102230246252E-16 instead
Submitted: 2010-04-09 05:03 UTC Modified: 2010-04-09 20:47 UTC
From: krenshala at koboldi dot net Assigned:
Status: Not a bug Package: Math related
PHP Version: 5.2.13 OS: Multiple
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: krenshala at koboldi dot net
New email:
PHP Version: OS:

 

 [2010-04-09 05:03 UTC] krenshala at koboldi dot net
Description:
------------
Math error for code that should be returning zero, but instead returns 1.1102230246252E-16 on multiple systems using multiple versions of PHP.

The problem is that when the input value is -3 the output value should be zero: 0.9 + (-3 * 0.3) = 0.9 - 0.9 = 0.  If the calculated value is non-zero the error does not occur.

I first saw the error on a WinXP (Home SP3, 32bit) system running PHP 5.2.9-1, but it also shows up on a MAC (10.6.2) with PHP 5.3.0 installed.  I'm in the process of upgrading PHP (to 5.2.13) on my Gentoo box to test it there but haven't had a chance to do so yet.

Test script:
---------------
my_function(-3);

function my_function($input){
  $output = 1;
  if($input <= 0)
    $output = 0.9 + ($input * 0.3);
  // the above should give 0.9 - 0.9 = 0
  echo "Verifying values: 0.9 - ".($input * 0.3)." is supposed to be zero?\n";
  echo "Input: $input\tOutput: $output\n";
  return $output;
}

Expected result:
----------------
should have received zero (0).

Actual result:
--------------
actually received: 1.1102230246252E-16

Patches

Add a Patch

Pull Requests

Add a Pull Request

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2010-04-09 05:05 UTC] rasmus@php.net
-Status: Open +Status: Bogus
 [2010-04-09 05:05 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://docs.sun.com/source/806-3568/ncg_goldberg.html
 
Thank you for your interest in PHP.

.
 [2010-04-09 05:12 UTC] rasmus@php.net
The fix here is to decide on your precision and do:

$output = round(0.9 + ($input * 0.3), 2);  // 2-decimal precision
 [2010-04-09 20:40 UTC] krenshala at koboldi dot net
tested it on my system at home and was able to reproduce it.

$ php --version
PHP 5.2.13-pl0-gentoo (cli) (built: Apr  9 2010 03:35:37)
Copyright (c) 1997-2010 The PHP Group
Zend Engine v2.2.0, Copyright (c) 1998-2010 Zend Technologies

$ cat test.php
echo "0.9 - 0.9 returns ".(0.9 - 0.9)."\n";
echo "0.9 + (-3 * .3) returns ".(0.9 + (-3 * .3))."\n";
echo "-0.9 + (3 * .3) returns ".(-0.9 + (3 * .3))."\n";
echo "0.8 + (-3 * .3) returns ".(0.8 + (-3 * .3))."\n";

$ php test.php
0.9 - 0.9 returns 0
0.9 + (-3 * .3) returns 1.11022302463E-16
-0.9 + (3 * .3) returns -1.11022302463E-16
0.8 + (-3 * .3) returns -0.1

Also, I can understand the multiplication increasing the precision used, from 1 to 3 significant digits in the function above. Jumping from 1E-3 to 1E-16 seems a bit much to me, however.  I'm reading the Floating Point doc you linked Rasmus in case it does address the issue.  From the little of it I've read so far it does seem to address at least some of what is happening here.

My concern is with the differences between the output of the different lines in my new script (this comment).  Assuming it is due to the floating point operation rounding/approximations mentioned in the doc, I'm assuming the difference shows up due to the multiplication.

... off to finish reading the Floating Point doc.
 [2010-04-09 20:47 UTC] rasmus@php.net
The important thing to take away from that doc is that computers can not store 
fractions accurately in an efficient manner.  They are much better and faster at 
dealing with integers.  In your particular example where you are using 0.3, that 
is one of many fractions that a computer cannot represent.  It is actually 
stored as 0.299999999999999988897769753748434595763683319091796875 which is very 
close to 0.3, but if you start doing math on it and any sort of exact 
comparisons, it simply won't work.  You can see this with this simple code:

ini_set('precision',64);
echo 0.3;
 [2010-04-09 21:01 UTC] krenshala at koboldi dot net
That, and the problem with storing 0.1 in binary.  I think those two issues are where my problem came from.

Thank you for your time and the information.  Hopefully this report (I won't call it a bug anymore ;) will help others as well since I did not see anything that matched it when searching before I submitted.
 
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Tue Jun 25 09:01:31 2024 UTC