Tom*_*omR 1 c floating-point rounding
我试图将8.475转到8.48(在C中为小数点后两位).问题是8.475内部表示为8.47499999999999964473:
double input_test =8.475;
printf("input tests: %.20f, %.20f \n", input_test, *&input_test);
Run Code Online (Sandbox Code Playgroud)
得到:
input tests: 8.47499999999999964473, 8.47499999999999964473
Run Code Online (Sandbox Code Playgroud)
所以,如果我有一个理想的圆函数,那么它将在8.475 = 8.4749999 ...到8.47.所以,内部圆函数不适合我.我看到在"下溢"的情况下出现舍入问题,因此我尝试使用以下算法:
double MyRound2( double * value) {
double ad;
long long mzr;
double resval;
if ( *value < 0.000000001 )
ad = -0.501;
else
ad = 0.501;
mzr = long long (*value);
resval = *value - mzr;
resval= (long long( resval*100+ad))/100;
return resval;
}
Run Code Online (Sandbox Code Playgroud)
这解决了"下溢"问题,它也适用于"溢出"问题.问题是有效值x.xxx99,这个函数错误地给出了更大的值(因为0.501中的0.001).如何解决这个问题,如何设计可以检测浮点表示问题的算法并且可以考虑这个问题呢?也许C已经有这么聪明的舍入功能?也许我可以为常量广告选择不同的值 - 这样的舍入错误的概率变为零(我主要使用最多4个十进制密码的货币值).
我已经阅读了所有关于浮点表示的popoular文章,我知道有棘手和无法解决的问题,但我的客户不接受这样的解释,因为客户端可以清楚地证明Excel处理(重现,舍入等)浮点数而不代表问题.
(当涉及到double类型的规范时,C和C++标准是有意灵活的;通常它是IEEE754 64位类型.所以你的观察结果是平台相关的).
您正在观察使用浮点类型的缺陷.
可悲的是,没有一个"开箱即用"的解决方案.(添加一个小的常量预舍入只会将问题推送到其他数字).
故事的道德:不要使用浮点类型来赚钱.
使用特殊货币类型或使用"便士"; 改为使用整数类型.
顺便说一句,Excel 确实使用IEEE754双精度浮点作为其数字类型,但它也有一些聪明的技巧.基本上它会仔细跟踪笑话数字,并且格式也很巧妙.这就是它如何准确地评估1/3 + 1/3 + 1/3.但即使它有时也会错误地计算金钱.