C++ C+中为0.501+;舍入算法,C+中的Excel舍入+;

C++ C+中为0.501+;舍入算法,C+中的Excel舍入+;,c++,algorithm,floating-point,rounding,C++,Algorithm,Floating Point,Rounding,我有以下常规舍入的遗留代码(向上舍入一半,类似于Excel舍入函数中的舍入)。我有关于这个代码的问题 为什么使用0.50倍加法?我理解,应该使用0.5加法来实现“四舍五入”条件,但为什么会有0.501?我们的经验表明,0.501在实践中效果良好,它引入的舍入误差(当RoundFloat与Excel舍入不同时)远小于0.5。为什么呢?浮点计算是否偏向于给出比理想情况下更小的值,并且0.501纠正了这些偏向 虽然0.501在大多数情况下效果良好,但某些值存在问题,例如RoundFloat(7.334

我有以下常规舍入的遗留代码(向上舍入一半,类似于Excel舍入函数中的舍入)。我有关于这个代码的问题

  • 为什么使用0.50倍加法?我理解,应该使用0.5加法来实现“四舍五入”条件,但为什么会有0.501?我们的经验表明,0.501在实践中效果良好,它引入的舍入误差(当RoundFloat与Excel舍入不同时)远小于0.5。为什么呢?浮点计算是否偏向于给出比理想情况下更小的值,并且0.501纠正了这些偏向
  • 虽然0.501在大多数情况下效果良好,但某些值存在问题,例如RoundFloat(7.33499999999,2)给出7.34,但这是错误的,正确答案应该是7.33。如何改进算法以获得正确的结果?可以尝试使用0.50000001而不是0.501,但在这种算法中总会有参数给出错误的结果<强>什么是正确算法,是否有Excel型圆舍入的内置C++函数?< /强>
  • 提前谢谢

    double LongLong( double value ) {
      long long l = ( long long ) value;
      return l;
    }
    
    double RoundFloat( double * value, double * tonearest ) {
      double ad;
      long long mzr; 
      double resval;
      if ( ( *tonearest < 0 ) || ( *tonearest > 6 ) ) return * value;
    
      if ( *value < 0.000000001 )
        ad = -0.501; 
      else
        ad = 0.501;  
    
      mzr = LongLong(*value);   
      resval = *value - mzr;
    
      switch ( ( long ) *tonearest )
      {   
       case 0 : resval= LongLong( resval+ad);
       case 1 : resval= LongLong( resval*10+ad)/10;
       case 2 : resval= LongLong( resval*100+ad)/100;
       case 3 : resval= LongLong( resval*1000+ad)/1000;
       case 4 : resval= LongLong( resval*10000+ad)/10000;
       case 5 : resval= LongLong( resval*100000+ad)/100000;
       case 6 : resval= LongLong( resval*1000000+ad)/1000000;
       default: resval= resval;
      }
       resval = resval+mzr;
       return resval;
    }
    
    double LongLong(双值){
    长l=(长l)值;
    返回l;
    }
    双圆浮点(双*值,双*音调最短){
    双重广告;
    长mzr;
    双重resval;
    if((*tonearest<0)| |(*tonearest>6))返回*值;
    如果(*值<0.000000001)
    ad=-0.501;
    其他的
    ad=0.501;
    mzr=LongLong(*值);
    resval=*值-mzr;
    开关((长)*音调最大)
    {   
    案例0:resval=LongLong(resval+ad);
    案例1:resval=LongLong(resval*10+ad)/10;
    案例二:resval=LongLong(resval*100+ad)/100;
    案例三:resval=LongLong(resval*1000+ad)/1000;
    案例四:resval=LongLong(resval*10000+ad)/10000;
    案例5:resval=LongLong(resval*100000+ad)/100000;
    案例6:resval=LongLong(resval*1000000+ad)/1000000;
    默认值:resval=resval;
    }
    resval=resval+mzr;
    返回resval;
    }
    
    (我将此答案限制为IEEE754浮点,这是Excel使用的。)

    Excel使用0.5(圆角轴),因为这是正确的做法。注意,0.5(作为二元有理数)可以用浮点精确表示

    使用0.501是任意的,过于不对称,并且显示出对浮点的理解不足

    由于数字略小于0.5,且0.5是最接近的可表示数字,因此可能会产生一些虚假效果。所以你的“少一点”数字会被四舍五入,即使它真的应该被四舍五入。但这更多的是因为这个数字一开始就不能准确地表示出来。因此,尽管0.5会给你一些奇怪的效果,但它平均比0.501或类似的效果更精确。而做一些事情,比如增加超过0.5,将搞乱四舍五入是最佳的情况

    虽然我集中讨论了0.5,但所有舍入效应都可以用相同的方式解释,尽管在其他情况下舍入轴本身可能无法表示

    像Excel一样,学会接受这种效果。(请记住,Excel可以以一种对用户隐藏这些效果的方式格式化数据,因此它似乎做了一些比实际更特殊的事情。)如果计算精度超过15位有效数字是绝对关键的,那么请使用支持任意精度的类。

    (我将此答案限制为IEEE754浮点,这是Excel使用的。)

    Excel使用0.5(舍入轴),因为这是正确的做法。请注意,0.5(作为二元有理数)可以用浮点精确表示

    使用0.501是任意的,过于不对称,并且显示出对浮点的理解不足

    你可以得到一些虚假的效果,因为一个数字比0.5小一点,而0.5是最接近的可表示数字数字被四舍五入,即使它真的应该被四舍五入。但这更多的是因为这个数字在一开始就不能准确地表示。因此,尽管0.5会给你一些奇怪的效果,但它平均比0.501或类似的数字更准确。而做一些事情,比如加上0.5以上,会把情况搞砸四舍五入是最佳选择

    虽然我集中讨论了0.5,但所有舍入效应都可以用相同的方式解释,尽管在其他情况下舍入轴本身可能无法表示

    学习使用效果,就像Excel一样。(请记住,Excel可以以一种对用户隐藏这些效果的方式格式化数据,因此它似乎在做一些比实际更特殊的事情。)如果计算精确到超过15位有效数字是绝对关键的,那么请使用支持任意精度的类