可能重复:
Retain precision with Doubles in java
Strange floating-point behaviour in a Java program
我正在制作直方图课程,我遇到了一个奇怪的问题。
以下是该课程的基础知识,有更多方法,但它们与问题无关。
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");
}
当我绘制频率时会出现问题。我创建了2个实例。 新直方图(0,1,10); 新的直方图(0,10,10);
这是他们输出的内容。
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
所以我的问题是,为什么我在第一个例子中获得了非常长的小数限制,但不是第二个?
答案 0 :(得分:5)
双打不准确。
这是因为有无限可能的实数,只有有限的位数来表示这些数字。
查看:what every programmer should know about floating point arithmetic
答案 1 :(得分:4)
因为在内部,计算机使用格式(二进制浮点) 它无法准确地表示像0.1,0.2或0.3 这样的数字。
编译或解释代码时,您的“0.1”已经存在 四舍五入到该格式的最接近的数字,这导致一个小的 甚至在计算发生之前就会出现舍入错误。
这说明了你的第一个例子。第二个只涉及整数,而不是分数,整数可以用二进制浮点格式(最多52位)精确表示。
答案 2 :(得分:3)
有些小数不能用double值精确表示。 0.3是其中一个值。
小于某个数字的所有整数值(我忘记了哪个)恰好具有双精度值的精确表示,因此您看不到近似值。
考虑我们如何看待数字:数字123表示为(1 * 100)+(2 * 10)+(3 * 1)。我们用10作为基础。二进制数使用两个。所以当你看一个数字的分数时,你怎么能通过增加2的个别幂来代表0.3?你不能。你能想到的最好的是大约0.30000000000000004(我必须看到确切的二进制数字才能看到它是如何达到的)。
答案 3 :(得分:0)
他们在第二种情况下变得圆滑。另请参阅Ruby - Multiplication issue - 这是同样的问题。