php php浮点数计算小数点后2位
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1604696/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
php float calculation 2 decimal point
提问by Shiro
Got a math calculation problem.
有一道数学计算题。
$a = 34.56
$b = 34.55
$ado some calculation to get this figure
$a做一些计算得到这个数字
$bis doing rounding to the nearest 0.05 to get this figure
$b正在四舍五入到最接近的 0.05 以获得这个数字
what happens is
发生的事情是
$c = $b - $a
supposedly it be -0.01, but I echo out the $c, which shows -0.00988888888888
应该是 -0.01,但我回显了$c,显示 -0.00988888888888
I try to use number_format($c, 2), but the output is 0.00,
我尝试使用number_format($c, 2),但输出为 0.00,
how can I make sure $aand $bis exactly 2 decimals, no hidden number at the back.
我怎样才能保证$a和$b正好是2位小数,在后面没有任何隐藏的号码。
in my php knowledge, number_formatis only able to format the display, but the value is not really 2 decimal,
在我的 php 知识中,number_format只能格式化显示,但该值不是真正的 2 位小数,
I hope I can get help from here. This really frustrated me.
我希望我能从这里得到帮助。这真的让我很沮丧。
回答by Charles Ma
Try sprintf("%.2f", $c);
尝试 sprintf("%.2f", $c);
Floating point numbers are represented in IEEE notation based on the powers of 2, so terminating decimal numbers may not be a terminating binary number, that's why you get the trailing digits.
浮点数以基于 2 的幂的 IEEE 表示法表示,因此终止的十进制数可能不是终止的二进制数,这就是您获得尾随数字的原因。
As suggested by Variable Length Coder, if you know the precision you want and it doesn't change (e.g. when you're dealing with money) it might be better to just use fixed point numbers i.e. express the numbers as cents rather than dollars
正如可变长度编码器所建议的那样,如果您知道所需的精度并且它不会改变(例如,当您处理金钱时),最好只使用定点数,即将数字表示为美分而不是美元
$a = 3456;
$b = 3455;
$c = $b - $a;
sprintf ("%.2f", $c/100.0);
This way, you won't have any rounding errors if you do a lot of calculations before printing.
这样,如果您在打印前进行大量计算,就不会出现任何舍入错误。
回答by cletus
Use round():
使用round():
$c = round($b - $a, 2);
Note:you can also choose the rounding mode as appropriate.
注意:您也可以根据需要选择舍入方式。
Edit:Ok I don't get what sprintf()is doing that number_format()isn't:
编辑:好的,我不明白sprintf()在做什么number_format()不是:
$c = number_format($b - $a, 2);
vs
对比
$c = sprintf("%.2f", $b - $a);
?
?
回答by Robert L
You can very neatly sidestep all of these issues simply by using the bcmath library.
只需使用 bcmath 库,您就可以非常巧妙地回避所有这些问题。
Just remember to read the documentation and be careful whether you are passing arguments as strings or as numeric datatypes.
请记住阅读文档并小心您是否将参数作为字符串或数字数据类型传递。
回答by PHP from Bulgaria
Native Calculation:
本机计算:
$a = 34.56;
$b = 34.55;
$c = $b - $a; // -0.010000000000005
Works as expected (! use always BC functions for real number calculations, the issue is for all C based platforms):
按预期工作(!始终使用 BC 函数进行实数计算,问题适用于所有基于 C 的平台):
$a = '34.56';
$b = '34.55';
$c = bcsub($b, $a, 4); // -0.0100
回答by jtaz
I also ran into this issue recently when doing calculations with floats. For example, I had 2 floats that when subtracted and formatted, the value was -0.00.
我最近在使用浮点数进行计算时也遇到了这个问题。例如,我有 2 个浮点数,当减去和格式化时,其值为 -0.00。
$floatOne = 267.58;
$floatTwo = 267.58;
$result = number_format($floatOne - floatTwo, 2);
print $result; //printed a string -0.00
What I did was:
我所做的是:
$result = abs($floatOne - $floatTwo);// Made the number positive
print money_format('%i', $result); // printed the desired precision 0.00
In my solution I know that floatOne will never be less than floatTwo. The money_formatfunction is only defined if the system has strfmon capabilities, Windows does not.
在我的解决方案中,我知道 floatOne 永远不会小于 floatTwo。该money_format功能只定义如果系统有能力的strfmon,Windows不会。
回答by Variable Length Coder
You've run into one of the traps of floating point numbers; that they cannot always represent exact decimal fractions. If you want exact decimal values, you're better off using integers and then dividing by the precision you want at the end.
您遇到了浮点数的陷阱之一;它们不能总是表示精确的十进制分数。如果您想要精确的十进制值,最好使用整数,然后在最后除以您想要的精度。
For example, if you're doing calculations in floats represeting Dollars (or your favorite currency), you may want to actually do your calculations in integer cents.
例如,如果您以代表美元(或您最喜欢的货币)的浮点数进行计算,您可能希望实际以整数美分进行计算。
回答by Selay
If still somebody reach this page with similar problems where floating number subtraction causes error or strange values. I want to explain this problem with a bit more details. The culprit is the floating point numbers. And different operating systems and different versions of programming languages can behave differently.
如果仍然有人遇到类似的问题,其中浮点数减法会导致错误或奇怪的值。我想用更多的细节来解释这个问题。罪魁祸首是浮点数。不同的操作系统和不同版本的编程语言可能会有不同的表现。
To illustrate the problem, I will explain why with a simple example below.
为了说明这个问题,我将在下面用一个简单的例子来解释原因。
It is not directly related to PHP and it is not a bug. However, every programmer should be aware of this issue.
它与 PHP 没有直接关系,也不是错误。但是,每个程序员都应该意识到这个问题。
This problem even took many lives two decades ago.
这个问题甚至在二十年前夺去了许多人的生命。
On 25 February 1991 this problem in floating number calculation in a MIM-104 Patriot missile battery prevented it intercepting an incoming Scud missile in Dhahran, Saudi Arabia, contributing to the death of 28 soldiers from the U.S. Army's 14th Quartermaster Detachment.
1991 年 2 月 25 日,MIM-104 爱国者导弹电池的浮点数计算问题使其无法在沙特阿拉伯宰赫兰拦截来袭的飞毛腿导弹,导致美国陆军第 14 军需分队的 28 名士兵死亡。
But why it happens?
但为什么会发生呢?
The reason is that floating point values represent a limited precision. So, a value might not have the same string representation after any processing. It also includes writing a floating point value in your script and directly printing it without any mathematical operations.
原因是浮点值表示有限的精度。因此,经过任何处理后,值可能不会具有相同的字符串表示形式。它还包括在您的脚本中写入一个浮点值并直接打印它而无需任何数学运算。
Just a simple example:
只是一个简单的例子:
$a = '36';
$b = '-35.99';
echo ($a + $b);
You would expect it to print 0.01, right? But it will print a very strange answer like 0.009999999999998
您希望它打印 0.01,对吗?但它会打印一个非常奇怪的答案,如 0.009999999999998
Like other numbers, floating point numbers double or float is stored in memory as a string of 0's and 1's. How floating point differs from integer is in how we interpret the 0's and 1's when we want to look at them. There are many standards how they are stored.
与其他数字一样,浮点数 double 或 float 作为 0 和 1 的字符串存储在内存中。浮点数与整数的不同之处在于我们在查看 0 和 1 时如何解释它们。它们的存储方式有很多标准。
Floating-point numbers are typically packed into a computer datum as the sign bit, the exponent field, and the significand or mantissa, from left to right....
浮点数通常作为符号位、指数字段和有效数或尾数从左到右打包到计算机数据中......
Decimal numbers are not well represented in binary due to lack of enough space. So, uou can't express 1/3 exactly as it's 0.3333333..., right? Why we can't represent 0.01 as a binary float number is for the same reason. 1/100 is 0.00000010100011110101110000..... with a repeating 10100011110101110000.
由于空间不足,十进制数字不能很好地用二进制表示。所以,你不能准确地表达 1/3,因为它是 0.3333333...,对吧?为什么我们不能将 0.01 表示为二进制浮点数也是出于同样的原因。1/100 是 0.00000010100011110101110000..... 重复 10100011110101110000。
If 0.01 is kept in simplified and system-truncated form of 01000111101011100001010 in binary,when it is translated back to decimal, it would be read like 0.0099999.... depending on system (64bit computers will give you much better precision than 32-bits). Operating system decides in this case whether to print it as it sees or how to make it in more human-readable way. So, it is machine-dependent how they want to represent it. But it can be protected in language level with different methods.
如果 0.01 以二进制的 01000111101011100001010 的简化和系统截断形式保存,当它转换回十进制时,它会读为 0.0099999.... 取决于系统(64 位计算机会给你比 32 位更好的精度)。在这种情况下,操作系统决定是按其所见打印还是如何以更易读的方式打印。因此,他们想要如何表示它取决于机器。但是可以通过不同的方法在语言级别进行保护。
If you format the result, echo number_format(0.009999999999998, 2); it will print 0.01.
如果格式化结果, echo number_format(0.009999999999998, 2); 它将打印 0.01。
It is because in this case you instruct how it should be read and how precision you require.
这是因为在这种情况下,您会指示应该如何阅读以及您需要多少精度。

