关于Java:为什么数学?Math.round(0.4999999999999999)返回1?

Why does Math.round(0.49999999999999994) return 1?

在下面的程序中,您可以看到每个略小于.5的值都向下取整,0.5除外。

1
2
3
4
5
6
7
8
9
for (int i = 10; i >= 0; i--) {
    long l = Double.doubleToLongBits(i + 0.5);
    double x;
    do {
        x = Double.longBitsToDouble(l);
        System.out.println(x +" rounded is" + Math.round(x));
        l--;
    } while (Math.round(x) > i);
}

印刷品

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
10.5 rounded is 11
10.499999999999998 rounded is 10
9.5 rounded is 10
9.499999999999998 rounded is 9
8.5 rounded is 9
8.499999999999998 rounded is 8
7.5 rounded is 8
7.499999999999999 rounded is 7
6.5 rounded is 7
6.499999999999999 rounded is 6
5.5 rounded is 6
5.499999999999999 rounded is 5
4.5 rounded is 5
4.499999999999999 rounded is 4
3.5 rounded is 4
3.4999999999999996 rounded is 3
2.5 rounded is 3
2.4999999999999996 rounded is 2
1.5 rounded is 2
1.4999999999999998 rounded is 1
0.5 rounded is 1
0.49999999999999994 rounded is 1
0.4999999999999999 rounded is 0

我正在使用Java 6更新31。


摘要P></

在Java 6(和presumably earlier),要实现round(x)is as this is a bug floor(x+0.5).1规范这一病理,precisely for Java 7周case.2不断implementation.3 mandates thisP></

the问题P></

确切的说因为是0.49999999999999994 0.5 + 1是双精度:P></

1
2
3
4
5
6
7
8
9
10
11
12
13
14
static void print(double d) {
    System.out.printf("%016x
"
, Double.doubleToLongBits(d));
}

public static void main(String args[]) {
    double a = 0.5;
    double b = 0.49999999999999994;

    print(a);      // 3fe0000000000000
    print(b);      // 3fdfffffffffffff
    print(a+b);    // 3ff0000000000000
    print(1.0);    // 3ff0000000000000
}

这是因为0.49999999999999994 has a指数比0.5小时,知道他们的增值,其尾数移is,and the ULP变得大。P></

the solutionP></

因为Java 7(for example,OpenJDK恩thus implements):4P></

1
2
3
4
5
6
public static long round(double a) {
    if (a != 0x1.fffffffffffffp-2) // greatest double value less than 0.5
        return (long)floor(a + 0.5d);
    else
        return 0;
}

<副>1。http:/ / / / 6 docs.oracle.com javaSE /文档/ / / / math.html Java API #圆朗28double 29 % %></分P></

<副>2。http:/ / / / bugs.java.com bugdatabase _ bug.do视图?_ id = 6430675 BUG(这simonnickerson for this to @测距)></分P></

<副>3。http:/ / / / docs.oracle.com javaSE 7 /文档/ / / / math.html Java API #圆朗28double 29 % %></分P></

<副>4。http:/ / / / / grepcode.com文件repository.grepcode.com JDK Java /根/ / / / 7u40 OpenJDK的B43 - Java /郎/ math.java # math.round 28double 29 % %></分P></


this appears to be known臭虫(臭虫在Java 6430675 surprising行为:math.round has been for which has 0x1.fffffffffffffp-2)在Java 7固定。P></


6:在JDK的源代码P></

1
2
3
public static long round(double a) {
    return (long)Math.floor(a + 0.5d);
}

7:在JDK的源代码P></

1
2
3
4
5
6
7
8
public static long round(double a) {
    if (a != 0x1.fffffffffffffp-2) {
        // a is not the greatest double value less than 0.5
        return (long)Math.floor(a + 0.5d);
    } else {
        return 0;
    }
}

when the value is 0.49999999999999994d JDK 6,因此,它将返回1楼和呼叫,但在JDK 7,检查是否ifcondition is the the number is the Greatest双值0.5 or not less。as the number is not in this家最伟大的双值else知道the less 0.5块,返回0。P></

你可以尝试0.49999999999999999d,which will返回1,but not because this is the Greatest 0,less双值0.5。P></


我有一样的JDK 1.6由32位,64位Java在线但我有7 0 0 rounded 0.49999999999999994 which is for the last is not印刷和在线。在VM的问题似乎是,不管一个人多,使用浮动点,你应该指望有什么不同的结果在不同的网络环境(位或32的CPU,64位模式)。P></

当使用布尔矩阵,round或位反转,等,这些可以使在巨大的差。P></

x64输出:P></

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
10.5 rounded is 11
10.499999999999998 rounded is 10
9.5 rounded is 10
9.499999999999998 rounded is 9
8.5 rounded is 9
8.499999999999998 rounded is 8
7.5 rounded is 8
7.499999999999999 rounded is 7
6.5 rounded is 7
6.499999999999999 rounded is 6
5.5 rounded is 6
5.499999999999999 rounded is 5
4.5 rounded is 5
4.499999999999999 rounded is 4
3.5 rounded is 4
3.4999999999999996 rounded is 3
2.5 rounded is 3
2.4999999999999996 rounded is 2
1.5 rounded is 2
1.4999999999999998 rounded is 1
0.5 rounded is 1
0.49999999999999994 rounded is 0


答案hereafter is of the />方法strictmath.round are the {数学定义,operationally asP></

1
(long)Math.floor(a + 0.5d)

双Arguments for。我厂usually expected this定义as the result of,它给surprising Rather比0,1,0x1.fffffffffffffp-2(0.49999999999999994 for)。P></

最伟大的0.49999999999999994 is the value less浮点值0.5。as a浮点值literal hexadecimal its is which is equal to 0x1.fffffffffffffp-2,(2 - 2 - 2 * 2(52)。=(0.5~2 54)。therefore the value of the sum,精确P></

1
(0.5 - 2^54) + 0.5

是1 - 2 54。This is between the已经两相邻的浮点数字(1 - 2和1 53)。在IEEE 754 arithmetic to the used最近甚至rounding回合模式java模式,当浮点结果是接近两inexact of the,表示浮点值which must be returned the result支架精确值;如果都是equally Close the last one which is its returned零位。这房子在正确的返回值(1)is from the less not the Greatest,值1。P></

while the method is defined as the operating on this is,甚surprising输入行为规范;the amended to something like是"to the closest桑圆长,rounding关系会跟进,"which allow the to be changed on this输入的行为。P></