如何在C中舍入8.475到8.48(考虑到表示问题的舍入函数)?减少问题发生的可能性

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处理(重现,舍入等)浮点数而不代表问题.

Bat*_*eba 6

(当涉及到double类型的规范时,C和C++标准是有意灵活的;通常它是IEEE754 64位类型.所以你的观察结果是平台相关的).

您正在观察使用浮点类型的缺陷.

可悲的是,没有一个"开箱即用"的解决方案.(添加一个小的常量预舍入只会将问题推送到其他数字).

故事的道德:不要使用浮点类型来赚钱.

使用特殊货币类型或使用"便士"; 改为使用整数类型.

顺便说一句,Excel 确实使用IEEE754双精度浮点作为其数字类型,但它也有一些聪明的技巧.基本上它会仔细跟踪笑话数字,并且格式也很巧妙.这就是它如何准确地评估1/3 + 1/3 + 1/3.但即使它有时也会错误地计算金钱.