我的报告应该返回
的内容SELECT brand, ROUND(SUM(count * price) / SUM(count), 2)
WHERE ... GROUP BY brand, ...;
问题是,我有时在我的perl代码中获得9990.32999999999992345而不是直接SQL请求返回的9990.33。
如果有的话,数字会在fetchrow_hashref之后立即开始。在不同的查询中,相同的数字可以是“好”或“坏”形式,但在任何特定查询中总是以相同的方式。
我该如何追踪?
答案 0 :(得分:9)
在此处阅读有关浮点精度问题的所有内容:http://en.wikipedia.org/wiki/Floating_point#Accuracy_problems
答案 1 :(得分:7)
正如mellamokb所说,你必须绕过你的浮点数。更重要的是,count
和price
可能意味着您正在计算某物的价格。 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);