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
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: 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

Add a Patch

Pull Requests

Add a Pull Request

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 Jun 16 21:01:29 2024 UTC