2009-10-22 140 views
13

有了另一个数学计算问题。PHP浮点运算2小数点

$a = 34.56 

$b = 34.55 

$a做一些计算得到这个数字

$b是做四舍五入最接近的0.05得到这个数字

发生什么事是

$c = $b - $a 

按说我应该是-0.01,但我回声出$c是显示-0.00988888888888

我尝试使用正umber_format($c, 2),但输出为0.00,

我怎么能保证$a$b正好是2位小数,在后面没有隐藏号码。

在我的PHP知识number_format只能格式化显示,但价值不是真的2位小数,

我希望我可以从这里得到帮助。这让我非常沮丧。

+0

调查php.ini中的'precision'以获得更多扫描,PHP范围内的更改。但是,请注意,您正在处理*有效数字*。 – 2009-10-22 02:40:12

回答

34

尝试sprintf("%.2f", $c);

浮点数表示基于2的幂IEEE符号,所以终止十进制数可能不是一个终止二进制数,这就是为什么你的结尾数字。如可变长度编码器所建议的,如果你知道你想要的精度并且它不会改变(例如,当你在处理金钱时),那么使用定点数字可能会更好,即将数字表示为美分而不是美元

$a = 3456; 

$b = 3455; 

$c = $b - $a; 

sprintf ("%.2f", $c/100.0); 

这样,如果您在打印之前进行大量计算,则不会有任何舍入错误。

+0

感谢您的回答,唯一的方法是格式化输出,除了使用String之外,不可能将其设置为2位十进制。 – Shiro 2009-10-22 02:27:16

+0

如果您想将其设置为2位小数,则应该使用定点数字,而不是浮点数。请参阅可变长度编码器的答案。 – 2009-10-22 23:35:43

+0

我真的不明白“定点”数字意味着什么,你能否提供一些例子?非常感谢! – Shiro 2009-10-23 02:43:47

12

使用round()

$c = round($b - $a, 2); 

注:你也可以选择舍入模式为适当。

编辑:好,我没有得到什么sprintf()就是干这个number_format()是不是:

$c = number_format($b - $a, 2); 

VS

$c = sprintf("%.2f", $b - $a); 

+0

可能没有什么,但是sprintf()对于像我这样习惯于C的人来说更有趣。同时还可以节省一个'$ foo = number_format($ b - $ a,2)。 “苹果!”,而不是写'$ foo = sprintf(“%。2f苹果!”,$ b - $ a)' - 在我看来,它更加优雅。 – 2009-10-22 02:38:00

+0

圆形的岩石,也许是因为现在我所知道的,仍然在学习。 – Newb 2009-10-23 02:53:13

2

你碰到的浮点数的陷阱之一;他们不能始终代表确切小数。如果你想确切的十进制值,你就要去使用整数,然后你要在最后的精度将更好。

例如,如果你正在做计算在浮动represeting美元(或您最喜欢的货币),你可能想真正做你的计算整数美分。

+0

你能举个例子说明整数仙的工作原理吗?不是真的明白你的意思。非常感谢您的评论。 – Shiro 2009-10-22 04:22:58

+0

“整数美分”意味着,例如,$ 24.95的金额不应被存储为浮点24.95,而应存储为整数2495. $ 10.00的金额将被存储为整数1000.等等。 – 2010-02-17 05:36:17

2

只需使用bcmath库,您可以非常整齐地回避所有这些问题。

只记得阅读文档,并小心你是否将参数作为字符串或数字数据类型传递。

4

本地计算:

$a = 34.56; 
$b = 34.55; 
$c = $b - $a; // -0.010000000000005  

按预期工作(使用实数计算的总BC功能,这个问题是所有基于C平台!):

$a = '34.56'; 
$b = '34.55'; 
$c = bcsub($b, $a, 4); // -0.0100  
+0

为了进一步重复这一点。使用字符串来表示数据而不是float/double数据类型。然后使用BCMath函数来计算变量。要利用sprintf('%1 $ s',bcadd($ var1,$ var2));这同样适用于数据库数据存储。 http://php.net/manual/en/book.bc.php – fyrye 2013-09-05 04:07:23

3

我最近在用浮点数进行计算时遇到了这个问题。例如,我减去并格式化了2个浮点数,其值为-0.00。

$floatOne = 267.58; 
$floatTwo = 267.58; 
$result = number_format($floatOne - floatTwo, 2); 
print $result; //printed a string -0.00 

我所做的是:

$result = abs($floatOne - $floatTwo);// Made the number positive 
print money_format('%i', $result); // printed the desired precision 0.00 

在我的解决方案我知道floatOne绝不会小于floatTwo。 money_format函数仅在系统具有strfmon功能时才定义,Windows不会。

1

如果仍然有人到达这个页面,类似的问题在浮动数字减法导致错误或奇怪的值。 我想用更多的细节来解释这个问题。罪魁祸首是浮点数。 而不同的操作系统和不同版本的编程语言可以有不同的表现。

为了说明这个问题,我将用下面的一个简单例子来解释为什么。

它不是PHP直接相关,它不是一个错误。但是,每个程序员都应该知道这个问题。

这个问题甚至在二十年前花了很多生命。

1991年2月25日,MIM-104“爱国者”导弹电池中的浮点数计算问题阻止了它拦截在沙特阿拉伯首都达兰发射的飞毛腿导弹,导致28名美国陆军第14军需官支队士兵死亡。

但为什么会发生?

原因是浮点值表示有限的精度。所以,在任何处理之后,值可能 不具有相同的字符串表示。它也包括 包括在脚本中写入一个浮点值,并直接打印它,而不进行任何数学运算。

只是一个简单的例子:

$a = '36'; 
$b = '-35.99'; 
echo ($a + $b); 

你希望它打印0.01,对不对? 但它会打印一个非常奇怪的答案,如0.009999999999998

像其他数字一样,浮点数double或float作为0和1的字符串存储在内存中。浮点与整数的不同之处在于我们如何解释0和1,当我们想看看它们时。他们存储的标准有很多。

浮点数通常被包装成一个计算机基准作为符号位,指数字段,并且有效数或尾数,从左至右....

十进制数没有在二进制表示的井由于缺乏足够的空间。所以,你不能完全表达1/3,因为它是0.3333333 ...,对吧?为什么我们无法将0.01表示为二进制浮点数是出于同样的原因。 1/100是0.00000010100011110101110000 .....重复10100011110101110000.

如果0.01以简化和系统截断的形式保存在01000111101011100001010二进制文件中,那么当它翻译回十进制时,它将被读为0.0099999。 ...取决于系统(64位计算机会给你比32位更好的精度)。在这种情况下,操作系统决定是否按照它看到的那样打印它,或者如何以更易于阅读的方式打印它。所以,它是如何依赖机器来表示的。但它可以用不同的方法在语言层面上得到保护。

如果格式化结果,echo number_format(0.009999999999998,2);它会打印0.01。

这是因为在这种情况下,你指示应该如何阅读它,以及你需要的精度。