4

我在 Java 中有一个简单的划分:

float f = 19.7f/100;
System.out.println(f); // 0.19700001

double d = 19.7/100;
System.out.println(d); // 0.19699999999999998

为什么会这样?

4

4 回答 4

2

这是有史以来最常见的问题之一,所以我将在这里提出几点。

  1. 计算机只能表示有限数量的数字,因此在存储数字并随后将它们除法时必须进行四舍五入。这种四舍五入自然会产生错误,但如果您只想要 3 位精度,那么它们在您的情况下应该无关紧要。

  2. The behavior of rounding off is a bit unpredictable because computers store numbers in binary. So whereas 19.7 is a terminating decimal, the same number is a repeating decimal in binary -- 10011.10110011001100110011001100110011... ... so you can see that rounding off at an arbitrary point will produce behavior that is not predictable from the terminating decimal expression.

于 2013-03-02T07:07:41.073 回答
0

Mystical 给出的链接是必读的,但它有点厚。试试这个网站以获得更适合初学者的版本。

tl;dr 是浮点运算总是需要舍入,并且由于具有更高的精度,双精度数的舍入方式与浮点数不同。这有点像如何将 55 四舍五入到最接近的 10 将是 60,但四舍五入到最接近的 10 将是 100。

在这种情况下,您不能准确地以浮点数或双精度数表示十进制数 0.197(或 19.7),因此每个数都会为您提供它可以表示的最接近该值的数字。双精度可以更接近一点,因为它具有更高的精度。

于 2013-03-02T07:02:42.737 回答
0

Java 使用 IEEE754 浮点数来处理它的浮点数和双精度数。本标准设计为无法准确表示以 10 为底的以 2 为底的数字。请参阅此处http://en.wikipedia.org/wiki/IEEE_floating_point

以下不完全是标准,而是一个示例,只是为了让您了解为什么基数为 2 的浮点数不适合其他基数。

基数 2 = 基数 10
 0001 = 0001 -> 从 0*8 + 0*4 + 0*2 + 1*1
 0010 = 0002 -> 从 0*8 + 0*4 + 1*2 + 0*1
 0011 = 0003 -> 从 0*8 + 0*4 + 1*2 + 1*1
 0100 = 0004 -> 从 0*8 + 1*4 + 0*2 + 0*1
 0101 = 0005 -> 从 0*8 + 1*4 + 0*2 + 1*1
                   8 = 2^3, 4 = 2^2, 2=2^1 和 1 = 2^0

然后
基数 2 = 基数 10
 .0000 = .0000 -> 从 0*1 + 0.5*0 + 0.25*0 + 0.125*0 + 0.0625*0
 .0001 = .0625 -> 从 0*1 + 0.5*0 + 0.25*0 + 0.125*0 + 0.0625*0
 .0010 = .1250 -> 从 0*1 + 0.5*0 + 0.25*0 + 0.125*0 + 0.0625*0
 .0011 = .1875 -> 从 0*1 + 0.5*0 + 0.25*0 + 0.125*0 + 0.0625*0
 .0100 = .2500 -> 从 0*1 + 0.5*0 + 0.25*0 + 0.125*0 + 0.0625*0
 .0101 = .3125 -> 从 0*1 + 0.5*0 + 0.25*0 + 0.125*0 + 0.0625*0
 .0110 = .3750 -> 从 0*1 + 0.5*0 + 0.25*0 + 0.125*0 + 0.0625*0
 .0111 = .4375 -> 从 0*1 + 0.5*0 + 0.25*0 + 0.125*0 + 0.0625*0
 .1000 = .5000 -> 从 0*1 + 0.5*0 + 0.25*0 + 0.125*0 + 0.0625*0
 .1001 = .5625 -> 从 0*1 + 0.5*0 + 0.25*0 + 0.125*0 + 0.0625*0
 .1010 = .6250 -> 从 0*1 + 0.5*0 + 0.25*0 + 0.125*0 + 0.0625*0
 .1011 = .6875 -> 从 0*1 + 0.5*0 + 0.25*0 + 0.125*0 + 0.0625*0
 .1100 = .7500 -> 从 0*1 + 0.5*0 + 0.25*0 + 0.125*0 + 0.0625*0
 .1101 = .8125 -> 从 0*1 + 0.5*0 + 0.25*0 + 0.125*0 + 0.0625*0
 .1110 = .8700 -> 从 0*1 + 0.5*0 + 0.25*0 + 0.125*0 + 0.0625*0
 .1111 = .9325 -> 从 0*1 + 0.5*0 + 0.25*0 + 0.125*0 + 0.0625*0

                   1 = 2^0, 0.5 = 2^-1, 0.25=2^-2 和 0.125 = 2^-3

如你看到的。4 位浮点数只能表示从 0 到 0.9325 的以 10 为基数的数字,间隙为 0.0625。这也意味着它不能做 0.1, 0.2, 0.3 ....

由于实际标准使用更多位以及使用数字移位技术。它实际上可以表示比这个例子更多的数字,但限制仍然相同。因此,当您划分某个值并且结果不属于其中之一时……JVM会将其移至最接近的值。

希望这能解释一下。

于 2013-03-02T07:19:38.057 回答
0

不是因为除法,问题是 1.7f != 1.7 由于精度损失。我们可以看看我们的值的位表示

    float f = 19.7f; 
    double d = 19.7;
    System.out.println(Double.doubleToLongBits(f)); 
    System.out.println(Double.doubleToLongBits(d));

输出

4626238274938077184
4626238274723328819
于 2013-03-02T07:14:40.247 回答