php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #60892 money_format returning inconsistent results
Submitted: 2012-01-26 14:47 UTC Modified: 2012-01-27 04:07 UTC
Votes:2
Avg. Score:4.0 ± 1.0
Reproduced:2 of 2 (100.0%)
Same Version:2 (100.0%)
Same OS:1 (50.0%)
From: gregs at net-virtual dot com Assigned:
Status: Not a bug Package: Math related
PHP Version: 5.3.9 OS: OSX
Private report: No CVE-ID: None
Welcome back! If you're the original bug submitter, here's where you can edit the bug or add additional notes.
If you forgot your password, you can retrieve your password here.
Password:
Status:
Package:
Bug Type:
Summary:
From: gregs at net-virtual dot com
New email:
PHP Version: OS:

 

 [2012-01-26 14:47 UTC] gregs at net-virtual dot com
Description:
------------
php -r '$a = 70687.465 + 8.930;$b = 70696.395;$c = 70687.464 + 8.936;printf("A: %s 
%s %.9f\n", $a, money_format("%.2n", $a), $a);printf("B: %s %s %.9f\n", $b, 
money_format("%.2n", $b), $b);printf("C: %s %s %.9f\n", $c, money_format("%.2n", 
$c), $c);'

Output:


A: 70696.395 70696.39 70696.395000000
B: 70696.395 70696.40 70696.395000000
C: 70696.4 70696.40 70696.400000000


Why is A not getting rounded up to 70696.40?


Test script:
---------------
php -r '$a = 70687.465 + 8.930;$b = 70696.395;$c = 70687.464 + 8.936;printf("A: %s %s %.9f\n", $a, money_format("%.2n", $a), $a);printf("B: %s %s %.9f\n", $b, money_format("%.2n", $b), $b);printf("C: %s %s %.9f\n", $c, money_format("%.2n", $c), $c);'

Expected result:
----------------
A: 70696.395 70696.40 70696.395000000
B: 70696.395 70696.40 70696.395000000
C: 70696.4 70696.40 70696.400000000


Actual result:
--------------
A: 70696.395 70696.39 70696.395000000
B: 70696.395 70696.40 70696.395000000
C: 70696.4 70696.40 70696.400000000


Patches

Pull Requests

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2012-01-26 14:54 UTC] gregs at net-virtual dot com
Here is a easier to read version of the test code (I also added one more):

$a = 70687.465 + 8.930;
$b = 70696.395;
$c = 70687.464 + 8.936;
$d = 70687.464 + 8.931;
printf("A: %s %s %.9f\n", $a, money_format("%.2n", $a), $a);
printf("B: %s %s %.9f\n", $b, money_format("%.2n", $b), $b);
printf("C: %s %s %.9f\n", $c, money_format("%.2n", $c), $c);
printf("D: %s %s %.9f\n", $d, money_format("%.2n", $d), $d);

Output:
A: 70696.395 70696.39 70696.395000000
B: 70696.395 70696.40 70696.395000000
C: 70696.4 70696.40 70696.400000000
D: 70696.395 70696.40 70696.395000000
 [2012-01-26 19:24 UTC] gregs at net-virtual dot com
Also I should add that if I do this:


$a = 8.930 + 70687.465;

instead of this:


$a = 70687.465 + 8.930;


It works.  The round() function seems to behave correctly in either case.  I 
cannot tell from this behavior if the problem is in number_format (which may not 
be calling round(), but doing its own flawed rounding) or if it something deeper 
in how PHP is storing floats/doubles.
 [2012-01-26 22:09 UTC] gregs at net-virtual dot com
This problem (if it is one) seems to extend to *printf* functions too:


$a = 8.930 + 70687.465;
$b = 70687.465 + 8.930;
$c = 70696.395000;
printf("A: %f, %.2f\n", $a, $a);
printf("B: %f %.2f\n", $b, $b);
printf("C: %f %.2f\n", $c , $c);'

Output:
A: 70696.395000, 70696.39
B: 70696.395000 70696.39
C: 70696.395000 70696.40

C version:


#include <stdio.h>

int main(void) {
    float a, b, c, d;
    a = 8.930 + 70687.465;
    b = 70687.465 + 8.930;
    c = 70696.395000;

    printf("A: %f %.2f\n", a, a);
    printf("B: %f %.2f\n", b, b);
    printf("C: %f %.2f\n", c, c);
}

Output:


A: 70696.398438 70696.40
B: 70696.398438 70696.40
C: 70696.398438 70696.40
 [2012-01-26 22:13 UTC] johannes@php.net
-Status: Open +Status: Bogus
 [2012-01-26 22:13 UTC] johannes@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.

As you said - it's related to the way PHP (and almost all computers) store floating point numbers.
 [2012-01-27 03:43 UTC] gregs at net-virtual dot com
With all due respect, you are not reading this.

sprintf('%.2f', $float);
number_format('%.2n', $float);

should *ROUND* these numbers, the behavior is incorrect
 [2012-01-27 03:45 UTC] gregs at net-virtual dot com
Sorry, I meant money_format('%.2n', $float);


In all of these cases the number should be rounded to 70696.40.
 [2012-01-27 04:07 UTC] gregs at net-virtual dot com
If anyone else runs across this, there is a good write-up here of the problem 
(with some proposals to fix it):

https://wiki.php.net/rfc/rounding

My take-away is that when using %f in any of the *printf* functions (which I 
presume money_format uses - what others I can only imagine), the only way to get 
true correctly rounded numbers is to explicitly round() the float before using it.
 [2012-01-27 11:58 UTC] gregs at net-virtual dot com
Here is another example:


php -r '$a = 70687.465 + 8.930;$b = 8.930 + 70687.465;$c = 70696.395000;printf("%f 
(%.2f)  %f (%.2f) %f (%.2f)\n", $a, $a, $b, $b, $c, $c);'
 
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Sun Oct 27 16:01:27 2024 UTC