由于前几天做了一个店铺评分的功能,本来SQL就比较简单,取平均值,四舍五入保留1位小数,但是测试测出了一个BUG。2.25的平均值四舍五入居然出现了2.2的取值。下面我们详细说一下。
1.先看看测试数据库,其实从这里有些人已经看出问题了,不过你知道为什么吗?下面我们添加几条数据。
2.我们写SQL 求一下平均值。
SELECT avg(part1),avg(part2) FROM test where name='zjw'
3.然后我们在平均值,保留一位小数四舍五入。
当时一下就懵逼了,为啥3.75四舍五入是正常的3.8,而2.25就是2.2呢?
然后我又试了一下:
这样看的没毛病啊,到底哪里出问题了呢?
后来在网上查资料,查了好几个都是废话,其中有一篇遇到了和我一样的问题,并且找出了原因,其实是查看了官方文档的Round函数说明:For exact-value numbers, ROUND() uses the “round half up” rule(对于精确的数值, ROUND 函数使用四舍五入)
For approximate-value numbers, the result depends on the C library. On many systems, this means that ROUND() uses the “round to nearest even” rule: A value with any fractional part is rounded to the nearest even integer. (对于近似值,则依赖于底层的C函数库,在很多系统中 ROUND 函数会使用“取最近的偶数”的规则)
这样就很明白了,在计算机的计算领域里,包括JAVA里的double,float都不算是精准的计算类型,所以Round的计算就默认的走了第二条规则。
其实在写店铺评分的时候,表是别人设计好的,也没有仔细看,后来出现了这个问题,我一看评分的字段类型是double,就感觉不是很对,因为咱知道在java里用double就有失精准的情况,所以一般都用bigdecimal进行精准计算,但是我很怀疑,MySQL也是这样吗?如果是这样那为什么呢?后来我又改了下类型在试了试。
我们把double改为decimal,在试一下sql
完美,原因也找到了,解决方案也找到了,不过楼主的那个没法改类型了,临上线几天了,没法评估改动的影响,就只取的平均值,然后在JAVA转化为bigdecimal进行的四舍五入。
踩过的坑,献给各位遇到此问题的小伙伴们!