Java:使用双重不准确

可能重复:
使用java中的双打保留精度
Java程序中奇怪的浮点行为

我正在进行直方图课程,我遇到了一个奇怪的问题。

以下是该类的基础知识,有更多方法,但它们与问题无关。

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 

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

一些小数不能用double值精确表示。 0.3是这​​些值之一。

所有小于某个数字的整数值(我忘了哪个)碰巧都有一个双精度值的精确表示,所以你看不到近似值。

考虑我们如何看待数字:数字123表示为(1 * 100)+(2 * 10)+(3 * 1)。 我们用10作为基础。 二进制数使用两个。 所以,当你看一个数字的分数时,你如何通过增加2的个别幂来代表0.3? 你不能。 你能想到的最好的是大约0.30000000000000004(我必须看到确切的二进制数字才能看到它是如何达到的)。

双打不准确。

这是因为有无限可能的实数和只有有限数量的位来表示这些数字。

看看: 每个程序员应该了解浮点运算

从浮点指南 :

因为在内部,计算机使用的格式(二进制浮点)无法准确地表示0.1,0.2或0.3之类的数字。

编译或解释代码时,“0.1”已经四舍五入到该格式中最接近的数字,这甚至在计算发生之前就会导致小的舍入误差。

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

他们在第二种情况下变得圆滑。 另请参阅Ruby – 乘法问题 – 这是同样的问题。