php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #27744 141.23 - 141.00 = 0.22999999999999 ?
Submitted: 2004-03-29 01:05 UTC Modified: 2004-03-31 11:40 UTC
From: t dot steve at ariadne-quatra dot com Assigned:
Status: Not a bug Package: Math related
PHP Version: * OS: *
Private report: No CVE-ID: None
View Developer Edit
Welcome! If you don't have a Git account, you can't do anything here.
If you reported this bug, you can edit this bug over here.
(description)
Block user comment
Status: Assign to:
Package:
Bug Type:
Summary:
From: t dot steve at ariadne-quatra dot com
New email:
PHP Version: OS:

 

 [2004-03-29 01:05 UTC] t dot steve at ariadne-quatra dot com
Description:
------------
Subtraction does not work as expected.

Windows 2000 Server
SP4
IIS5
PHP5RC1

Reproduce code:
---------------
$result=141.23-141.00;
echo $result;

(or 
$result=141.23-141;
echo $result;
 - same result)

Expected result:
----------------
0.23

Actual result:
--------------
0.22999999999999

Patches

Pull Requests

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2004-03-29 01:06 UTC] alan_k@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.
 
Thank you for your interest in PHP.

.
 [2004-03-30 12:07 UTC] garbo_doe at hotmail dot com
IMHO I think this is a bug. Of course there are problems with floatingpoint values in binary form, especially when rounded many times. But in an operation like <?php echo (string)(750 - 749.99) ?> it shouldn't return "0.00999999999999" but "0.01". 
I did a quick test in Delphi: showmessage(floattostr(750 - 749.99)); returns "0.01, not "0.00999999999999".

I had to solve it in PHP but multiplying with 100, then subtract and then divide the result by 100 again. 
It's not pretty :-D
(0.00999[infinite 9's] IS exactly the same as 0.01, but it should remember the "infinite" with a bit or something, so (1/3)*3 = 1 and not 0.999999999)

(this is similar as bug #8164)
 [2004-03-30 13:45 UTC] helly@php.net
That is the whole point of the answer. Floating point values are not accurate and are not nice. And we do not do a bunch of work just to make them look better in certain circumstances.
 [2004-03-30 19:47 UTC] alan_k@php.net
create table a ( b float,c float );
Query OK, 0 rows affected (0.11 sec)
 
mysql> insert into a (b,c) values (141.23,141);
Query OK, 1 row affected (0.07 sec)
 
mysql> select b-c from a;
+------------------+
| b-c              |
+------------------+
| 0.22999572753906 |
+------------------+
1 row in set (0.00 sec)


 [2004-03-30 19:59 UTC] rasmus@php.net
Guys, how in the world is PHP supposed to magically guess what precision you want results displayed in.  If you know you always want lower precision, set that in your php.ini file.  Or if you just want it temporarily simply do:

$old = ini_set('precision',2);
echo (string)(750 - 749.99);
ini_set('precision',$old);

 [2004-03-30 21:35 UTC] t dot steve at ariadne-quatra dot com
Hi!

I am sure I am something, apologies for that. :(

"Guys, how in the world is PHP supposed to magically guess what precision you want results displayed in."

141.23 - 141 _is_ precisely 0.23. If I was asking for 1/3, then I would understand the decimal places. But how come 141.23-141 turns out to have so many decimal places in the end instead of just being 0.23 - the mathematically correct and precise result?
 [2004-03-30 21:40 UTC] gschlossnagle@php.net
Floating point values in computers are never exact.  
It's a fact of life, and an issue that is not only 
encountered with PHP but other languages as well.
 [2004-03-31 03:12 UTC] helly@php.net
Since you don't believe us:
http://docs.sun.com/source/806-3568/ncg_goldberg.html
 [2004-03-31 06:41 UTC] garbo_doe at hotmail dot com
echo (string)(75000.00 - 74999.00); returns 1, not 0.9999999999. Is this a bug then? ;)

"Guys, how in the world is PHP supposed to magically guess what precision you want results displayed in."

Maybe a magicless solution would be: don't use greater precision then either the minuend or subtrahend (the one with greatest precision).

Thanks for you answers and for PHP - it's great! :-)

(I hope I'm not too annoying continuing this discussion...I sense some irritation, "we have already explained", on this matter :-)
 [2004-03-31 10:28 UTC] rasmus@php.net
For a computer there is simply no such thing as exactly 0.23, it is as simple as that.  When displaying floating point numbers, either use printf() and specify the number of significant digits you want or use PHP's precision setting.

As for this suggestion:

> Maybe a magicless solution would be: don't use greater 
> precision then either the minuend or subtrahend (the one 
> with greatest precision).

Reducing precision during the calculation would magnify rounding errors greatly when doing a series of operations on the floating point values.  You want to apply lower precision at the end at display time, not during the calculation.  And at display time we don't know what the precicion of the operands were that led to this value which is why you need to explicitly express what precision you want values displayed at.
 [2004-03-31 10:55 UTC] t dot steve at ariadne-quatra dot com
Guys, guys, guys... :)

I want to make one thing clear: No offense was meant, and I still think PHP is great, and that I learned something new - even though I think this is probably not the correct forum for that. :)

I never imagined this would turn out to be such a long discussion - it seems I accidentally touched on something that others came across too.

Just as pont of interest: We also use PHP for our (travel agency..) intra+extranet admin system, and among other things, we use PHP-generated forms to order hotel rooms for our clients. At times we get forms requesting a hotel room for "3.9999999.. nights...". :)) Now I know why.

Thanks again for all the reactions, and keep up the excellent work! :)
 [2004-03-31 11:06 UTC] garbo_doe at hotmail dot com
I'm sorry I keep posting :) (Maybe I'm just stupid. This will be my last post, maybe I'm plain wrong.) 

>Reducing precision during the calculation would magnify >rounding errors greatly when doing a series of operations >on the floating point values.

Yes. But for subtraction, the difference can never have "more decimals" (precision) than either its minuend or subtrahend, anything else introduces more error in multiple operations. Or?

In C++, if you substract a float (750.00f) from a float (749.99f), it will result in 0.0100098. *However*, if you do the same with double, insted of floats, it would result in 0.01 (I think). The first one, float substraction, is probably faster, the second is more "accurate". (I don't think that type of speed optimization is relevant to a php-script?)

Another option is ((a * 100) - (b * 100)) / 100; 

"100" would have to be modified to the "greatest" precision of either a or b. This will not "magnify rounding errors", because it will be exact. 

I'm only talking about subtraction.

What I'm looking for is somthing like "AUTO_PRECISION = yes" and it would do something like:

$old = ini_set('precision', max_decimals(750, 749.99));
echo (string)(750 - 749.99);
ini_set('precision',$old);

or use a C++ double instead of float (?).

Thanks for your patience! :)
 [2004-03-31 11:40 UTC] abies@php.net
'Exact' is not the same thing as 'no fractional part'. For numbers sufficiently large, the least significant digits can represent hundreds or thousands or greater, but this doesn't mean those digits are accurate.  
Some numbers *can* be represented exactly, but the fact that they can't be distinguished from numbers that can *not* be represented exactly is the whole point in fp arithmetic. Multiplying by a large number cannot restore the accuracy that was lost by storing the (exact) number in a double.

BTW PHP already uses doubles internally for its float type.
 
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Sat Dec 14 13:01:26 2024 UTC