在C#中舍入double值

Rounding double values in C#

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
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,但这对于这个问题来说太过局限,我不知道要设置的正确公差是什么。谢谢你的帮助。


如Kibbee所指出的,使用decimal的示例

1
2
3
double d = 1.275;
Math.Round(d, 2);          // 1.27
Math.Round((decimal)d, 2); // 1.28


1
2
3
double d = 1.2345;

Math.Round(d, 2);

上面的代码应该可以做到这一点。


吉米答案中提供的使用十进制转换的例子并没有回答这个问题,因为它们没有显示如何按要求将一个双精度值舍入到任何舍入精度值。我相信使用十进制转换的正确答案如下:

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

因为它使用十进制转换,所以这个解决方案会受到Jeppe Stig Nielsen在对Jimmy答案的评论中提到的转换错误的影响。

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


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

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

2