|
php.net | support | documentation | report a bug | advanced search | search howto | statistics | random bug | login |
[2012-04-20 13:38 UTC] ubuntu at spacetrace dot org
Description:
------------
if you round with money_format, some small numbers with 0.005 are rounded down instead of up.
Numbers bigger than 63.5 are all rounded falsly down like with floor()
Test script:
---------------
for($i=0;$i<70;$i++) {
echo($i.'.005 =>'.money_format('%.2i',$i+0.005).'<br>');
if($i<10) echo($i.'.00500000000000001=>'.money_format('%.2i',$i+0.00500000000000001).'<br>');
}
Expected result:
----------------
0.005 =>0.01
0.00500000000000001=>0.01
1.005 =>1.01
1.00500000000000001=>1.01
2.005 =>2.01
2.00500000000000001=>2.01
3.005 =>3.01
3.00500000000000001=>3.01
4.005 =>4.01
4.00500000000000001=>4.01
5.005 =>5.01
5.00500000000000001=>5.01
6.005 =>6.01
6.00500000000000001=>6.01
7.005 =>7.01
7.00500000000000001=>7.01
8.005 =>8.01
8.00500000000000001=>8.01
9.005 =>9.01
9.00500000000000001=>9.01
10.005 =>10.01
11.005 =>11.01
12.005 =>12.01
13.005 =>13.01
14.005 =>14.01
15.005 =>15.01
16.005 =>16.01
...
Actual result:
--------------
0.00500000000000001=>0.01
1.005 =>1.00
1.00500000000000001=>1.01
2.005 =>2.00
2.00500000000000001=>2.00
3.005 =>3.00
3.00500000000000001=>3.00
4.005 =>4.00
4.00500000000000001=>4.00
5.005 =>5.00
5.00500000000000001=>5.00
6.005 =>6.00
6.00500000000000001=>6.00
7.005 =>7.00
7.00500000000000001=>7.00
8.005 =>8.01
8.00500000000000001=>8.01
9.005 =>9.01
9.00500000000000001=>9.01
10.005 =>10.01
11.005 =>11.01
12.005 =>12.01
13.005 =>13.01
14.005 =>14.01
15.005 =>15.01
16.005 =>16.00
17.005 =>17.00
18.005 =>18.00
19.005 =>19.00
20.005 =>20.00
21.005 =>21.00
22.005 =>22.00
23.005 =>23.00
24.005 =>24.00
25.005 =>25.00
26.005 =>26.00
27.005 =>27.00
28.005 =>28.00
29.005 =>29.00
30.005 =>30.00
31.005 =>31.00
32.005 =>32.01
33.005 =>33.01
34.005 =>34.01
35.005 =>35.01
36.005 =>36.01
37.005 =>37.01
38.005 =>38.01
39.005 =>39.01
40.005 =>40.01
41.005 =>41.01
42.005 =>42.01
43.005 =>43.01
44.005 =>44.01
45.005 =>45.01
46.005 =>46.01
47.005 =>47.01
48.005 =>48.01
49.005 =>49.01
50.005 =>50.01
51.005 =>51.01
52.005 =>52.01
53.005 =>53.01
54.005 =>54.01
55.005 =>55.01
56.005 =>56.01
57.005 =>57.01
58.005 =>58.01
59.005 =>59.01
60.005 =>60.01
61.005 =>61.01
62.005 =>62.01
63.005 =>63.01
64.005 =>64.00
65.005 =>65.00
66.005 =>66.00
67.005 =>67.00
68.005 =>68.00
69.005 =>69.00
from 64 on all numbers are rounded down like floor()
PatchesPull RequestsHistoryAllCommentsChangesGit/SVN commits
|
|||||||||||||||||||||||||||
Copyright © 2001-2025 The PHP GroupAll rights reserved. |
Last updated: Wed Oct 29 08:00:01 2025 UTC |
money_format('%.2i',1.005) results in 1.00 and money_format('%.2i',7.005) results in 7.01 this is definitely a bug. you only showed me, the reason, how the bug was created. but it should still be solved! Or, if you say, the syntax is not correct, cause you provoke an unpredictable behaviour with '%.2i' then shouldnt that throw an error notice at least? why cannot the php-supporters use the same algorythm, like in function round(), where there IS rounded correctly(i meant: money_format('%.2i',8.005) results in 8.01)This is getting a bit tiresome. There is no bug here. Maybe you will understand it this way. Try running this: <?php ini_set('precision',32); $ns = array(1.005, 7.005, 8.005); foreach($ns as $n) { echo "$n ".money_format('%.2i', $n)."\n"; } The output on my machine is: 1.004999999999999893418589635985 1.00 7.004999999999999893418589635985 7.00 8.0050000000000007815970093361102 8.01 That is, 1.005 can't actually be represented accurately and it ends up being slightly below 1.005 which means when you round it you get 1.00. And 8.005 ends up being represented as slightly larger than 8.005 so when you round it you get 8.01. It makes perfect sense. Simply add a fuzz factor to your floating point values to the appropriate precision you care about. Or, as most people know, when dealing with money, don't use floating point at all. Work in integers.No, that won't work. Often the value comes from expressions that always generate lots of digits. eg. number_format('%.2i', 1/3) What would you expect that to do? You wold get a notice every single time even though there may not be any relevant loss of precision. There are just certain things you need to eventually learn when you start programming.The same bug is in sprintf("%01.2f",7.005); which results in 7.00 while sprintf("%01.2f",8.005); results in 8.01Please stop. This is not a PHP-specific issue. This is just how floating point works in computers. You will need to learn how to deal with it. For example, compile this C program: #include <stdio.h> int main(char *argv[], int argc) { printf("%01.2f\n",7.005); printf("%01.2f\n",8.005); } cc f.c -o f then run it: ./f you get: 7.00 8.01 Which is exactly the same as the PHP results. PHP is a thin layer over C.