关于浮点:Java:使用双精度不准确

Java: Inaccuracy using double

本问题已经有最佳答案,请猛点这里访问。

Possible Duplicate:
Retain precision with Doubles in java
Strange floating-point behaviour in a Java program

我正在做一个柱状图类,我遇到了一个奇怪的问题。

这是这个类的基础知识,还有更多的方法,但它们与这个问题无关。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
private int[] counters;
private int numCounters;
private double min, max, width;

public Histogram(double botRange, double topRange, int numCounters) {
    counters = new int[numCounters];
    this.numCounters = numCounters;
    min = botRange;
    max = topRange;
    width = (max - min) / (double) numCounters;
}

public void plotFrequency() {
    for (int i = 0; i < counters.length; i++) {
        writeLimit(i * width, (i + 1) * width);
        System.out.println(counters[i]);
    }
}

private void writeLimit(double start, double end) {
    System.out.print(start +" <= x <" + end +"\t\t");
}

当我画出频率图时,问题就发生了。我创建了两个实例。新的柱状图(0,1,10);新的柱状图(0,10,10);

这就是他们的输出。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
Frequecy
0.0 <= x < 0.1      989
0.1 <= x < 0.2      1008
0.2 <= x < 0.30000000000000004      1007
0.30000000000000004 <= x < 0.4      1044
0.4 <= x < 0.5      981
0.5 <= x < 0.6000000000000001       997
0.6000000000000001 <= x < 0.7000000000000001        1005
0.7000000000000001 <= x < 0.8       988
0.8 <= x < 0.9      1003
0.9 <= x < 1.0      978

Frequecy
0.0 <= x < 1.0      990
1.0 <= x < 2.0      967
2.0 <= x < 3.0      1076
3.0 <= x < 4.0      1048
4.0 <= x < 5.0      971
5.0 <= x < 6.0      973
6.0 <= x < 7.0      1002
7.0 <= x < 8.0      988
8.0 <= x < 9.0      1003
9.0 <= x < 10.0     982

所以我的问题是,为什么我在第一个例子中得到了很长的小数极限,而不是第二个例子?


双打不准确。

这是因为有无限可能的实数,并且只有有限位数来表示这些数。

看看:每个程序员都应该知道什么是浮点运算


从浮点指南:

Because internally, computers use a format (binary floating-point)
that cannot accurately represent a number like 0.1, 0.2 or 0.3 at all.

When the code is compiled or interpreted, your"0.1" is already
rounded to the nearest number in that format, which results in a small
rounding error even before the calculation happens.

这就是你的第一个例子。第二个只涉及整数,而不是分数,整数可以以二进制浮点格式(最多52位)精确表示。


有些小数不能用双精度值精确表示。0.3是这些值之一。

小于某个数字的所有整数值(我忘记了哪一个)恰好由一个双精度值表示,所以您看不到近似值。

考虑一下我们如何看待数字:数字123表示为(1*100)+(2*10)+(3*1)。我们以10为基地。二进制数使用二。所以当你看一个数的分数时,你怎么能用2的幂来表示0.3呢?你不能。你能想到的最好的是大约0.30000000000000004(我必须要看到确切的二进制数字才能看到它是如何达到这个数字的)。


他们在第二个案子中被驳回了。另请参见Ruby-乘法问题-它是同一个问题。