有时,圆形数字返回为“0.999999999992345”

时间:2011-02-18 15:54:33

标签: mysql perl floating-accuracy

我的报告应该返回

的内容
SELECT brand, ROUND(SUM(count * price) / SUM(count), 2) 
    WHERE ... GROUP BY brand, ...; 

问题是,我有时在我的perl代码中获得9990.32999999999992345而不是直接SQL请求返回的9990.33。

如果有的话,数字会在fetchrow_hashref之后立即开始。在不同的查询中,相同的数字可以是“好”或“坏”形式,但在任何特定查询中总是以相同的方式。

我该如何追踪?

6 个答案:

答案 0 :(得分:9)

在此处阅读有关浮点精度问题的所有内容:http://en.wikipedia.org/wiki/Floating_point#Accuracy_problems

答案 1 :(得分:7)

正如mellamokb所说,你必须绕过你的浮点数。更重要的是,countprice可能意味着您正在计算某物的价格。 As this page解释FLOAT和DOUBLE数据类型,计算是近似的,而对于DECIMAL,它们是精确的。对于您的特定示例,机会很低会产生问题,但如果您使用price进行大量计算则不会。通常的规则是始终使用确切的数据类型来计算价格。

答案 2 :(得分:4)

在屏幕上显示浮点数时,始终将其浮动。并将其作为显示的最后一步。任何中间操作都有可能导致这样的问题。

答案 3 :(得分:2)

我可以想到几个原因,但首先是:

在你的ROUND周围添加CONCAT( '', ... )会有什么不同吗?你使用的是什么版本的perl? perl -V:nvtype报告什么?

答案 4 :(得分:2)

33/100是二进制的周期数,就像1/3是十进制的周期数一样。

$ perl -e'printf "%.20f\n", 0.33'
0.33000000000000001554

因此,将无限存储空间存储为浮点数。为了避免这个问题,你需要将数字存储为字符串,要么是早期(在查询之前是浮动),要么是晚期(通过舍入)。

答案 5 :(得分:1)

这是浮点数固有的问题。这是一个设计特征,而不是一个缺陷。

确保从数据库返回的值不是浮点值,而是字符串或小数。 (如果`price`和`count`的数据类型都是DECIMAL,那么结果表达式应该是DECIMAL。

如果其中任何一个是浮点数,那么您可以转换为DECIMAL ...

SELECT brand, CONVERT( SUM(count * price) / SUM(count), DECIMAL(18,2) ) 
    WHERE ... GROUP BY brand, ...; 

或转换为字符串

SELECT brand, CONVERT(CONVERT( SUM(count * price) / SUM(count), DECIMAL(18,2)),CHAR)
    WHERE ... GROUP BY brand, ...; 

您可以让转换为DECIMAL为您进行舍入。如果将DECIMAL或VARHCAR返回给Perl,则应该避免浮点问题。

更一般地说,要处理Perl中浮点的表示(舍入),可以使用sprintf函数进行格式化,例如

my $rounded_val = sprintf(%.2f, $float_val);