代码之家  ›  专栏  ›  技术社区  ›  Steve

C中的舍入双精度值#

  •  30
  • Steve  · 技术社区  · 15 年前

    我想要一个C中双值的舍入方法。它需要能够将一个双精度值舍入到任何舍入精度值。我手头的代码如下:

    public static double RoundI(double number, double roundingInterval) {
    
        if (roundingInterval == 0.0)
        {
            return;
        }
    
        double intv = Math.Abs(roundingInterval);
        double sign = Math.Sign(number);
        double val = Math.Abs(number);
    
        double valIntvRatio = val / intv;
        double k = Math.Floor(valIntvRatio);
        double m = valIntvRatio - k;
    
        bool mGreaterThanMidPoint = ((m - 0.5) >= 1e-14) ? true : false;
        bool mInMidpoint = (Math.Abs(m - 0.5) < 1e-14) ? true : false;
        return (mGreaterThanMidPoint || mInMidpoint) ? sign * ((k + 1) * intv) : sign * (k * intv);
    }
    

    所以Roundi(100,3)应该是99,Roundi(1.2345,0.001)应该是1.235。

    问题是,roundi(1.275,0.01)返回1.27,而不是1.28。这是因为当执行double valintvratio=val/intv时,即double valintvratio=1.275/0.01,它给出0.127499999999。我知道这是任何编程语言中双重表示的一个问题。我的问题是,有没有一个标准的代码来做这样的事情,而不需要担心双精度?这里,我将公差设置为1e-14,但这对于这个问题来说太过局限,我不知道要设置的正确公差是什么。谢谢你的帮助。

    4 回复  |  直到 9 年前
        1
  •  42
  •   PaulStock    11 年前

    使用示例 decimal 作为 基比 指出

    double d = 1.275;
    Math.Round(d, 2);          // 1.27
    Math.Round((decimal)d, 2); // 1.28 
    
        2
  •  5
  •   AceMark    15 年前
    double d = 1.2345;
    
    Math.Round(d, 2);
    

        3
  •  2
  •   Jonas Elfström    13 年前

    如果你真的需要 double 只需在下面替换它,它就可以工作了,但是要用到二进制浮点运算的常见精度问题。

    最肯定的是,实现“四舍五入”(几乎是一种银行家的四舍五入)的方法比我在下面胡乱摆弄绳子要好。

    public static decimal RoundI(decimal number, decimal roundingInterval)
    {
       if (roundingInterval == 0) { return 0;}
    
       decimal intv = Math.Abs(roundingInterval);
       decimal modulo = number % intv;
       if ((intv - modulo) == modulo) {
           var temp = (number - modulo).ToString("#.##################");
           if (temp.Length != 0 && temp[temp.Length - 1] % 2 == 0) modulo *= -1;
       }
        else if ((intv - modulo) < modulo)
            modulo = (intv - modulo);
        else
            modulo *= -1;
    
        return number + modulo;
    }
    
        4
  •  2
  •   R.T.    9 年前

    使用十进制转换的示例 吉米 的答案不回答问题,因为它们不显示如何按要求将双精度值舍入为任何舍入精度值。我相信使用十进制转换的正确答案如下:

        public static double RoundI(double number, double roundingInterval)
        {
            return (double)((decimal)roundingInterval * Math.Round((decimal)number / (decimal)roundingInterval, MidpointRounding.AwayFromZero));
        }
    

    因为它使用十进制转换,所以此解决方案会受到以下提到的转换错误的影响: 杰佩·斯蒂格·尼尔森 在他的评论中 吉米 的答案。

    另外,请注意,我指定了MidpointRounding.awayFromZero,因为这与请求者的规范一致,Roundi(1.2345,0.001)应该给出1.235。