C++和Delphi工程0.5四舍五入问题的的排查

Posted 李迟

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C++和Delphi工程0.5四舍五入问题的的排查相关的知识,希望对你有一定的参考价值。

最近加班时,在测试数据过程发现1分钱的误差问题。经过排查,发现原来是数据库本身小数点存储的问题,但修改数据表类型已不可能,因此须改代码以适应之。本文记录了排查的过程。

发现问题

那天深夜,由外部人员核对数据时,发现某个字段数据与手工计算的结果少了1分钱,主任工十分关注,那天搞到深夜,经过多种语言在不同系统中测试发现的确如此,当时还不知道原因,因临近上线,最后决定手动修改错误的字段的数值,以确保按时上线。

排查过程

先是在用代码复现算法过程,将计算过程打印出来,均未发现异常,但最终结果依然出错。

后来发现,原来是数据表本身有误差。生产环境使用 oracle 数据库,该字段数值存储的是以元为单位的金额,本身只有2个小数点,但字段类型是 FLOAT,大小是 126。比如数值2.01,存储时会变成2.0099999999999998 。如果与0.5相乘,则变成1.0049999999999999,转换成分,变成100.49999999999999,此时四舍五入,结果为100。如果按2.01计算,中间值为1.005,最终四舍五入的结果为101。误差就是这样来的。在代码中用printf打印,应该自动做了转换,即100.49999999999999会以100.5的形式输出,但只要做四舍五入操作,就会变成100,可能在计算机系统中,100.49999999999999100.500000000是不相等的。

这个问题是在 Delphi 工程中发现,用 C++ 语言在 Linux系统,Golang 语言在 Windows 系统测试,表现一样。

问题解决

试过将原始的数值先四舍五入再进行计算,无法解决。最后的方法是在计算结果中添加一个很小很小浮点数,比如0.00000001,填补存在的误差,经核对,可以达到预期结果。但此法始终不是正道。

小结

个人认为最根本的解决方法是修改数据表的类型,或者修改数值表示形式,以减少小数点为原则,如单位为元,则转换为分;单位为公里,则转换为米,因为实际应用中,最小的单位就是分和米。但在生产环境已有的机制且对修改结果无法评估情况下,只能修改代码来解决。

以上是关于C++和Delphi工程0.5四舍五入问题的的排查的主要内容,如果未能解决你的问题,请参考以下文章

一个C++工程内存泄漏问题的排查及重现工程

c++中的一些计算的问题

一个C++工程CPU占用100%问题的排查

一个C++工程CPU占用100%问题的排查

一个生产环境C++工程段错误的排查

一个生产环境C++工程段错误的排查