我在 Java 中有一个简单的划分:
float f = 19.7f/100;
System.out.println(f); // 0.19700001
double d = 19.7/100;
System.out.println(d); // 0.19699999999999998
为什么会这样?
我在 Java 中有一个简单的划分:
float f = 19.7f/100;
System.out.println(f); // 0.19700001
double d = 19.7/100;
System.out.println(d); // 0.19699999999999998
为什么会这样?
这是有史以来最常见的问题之一,所以我将在这里提出几点。
计算机只能表示有限数量的数字,因此在存储数字并随后将它们除法时必须进行四舍五入。这种四舍五入自然会产生错误,但如果您只想要 3 位精度,那么它们在您的情况下应该无关紧要。
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.
Mystical 给出的链接是必读的,但它有点厚。试试这个网站以获得更适合初学者的版本。
tl;dr 是浮点运算总是需要舍入,并且由于具有更高的精度,双精度数的舍入方式与浮点数不同。这有点像如何将 55 四舍五入到最接近的 10 将是 60,但四舍五入到最接近的 10 将是 100。
在这种情况下,您不能准确地以浮点数或双精度数表示十进制数 0.197(或 19.7),因此每个数都会为您提供它可以表示的最接近该值的数字。双精度可以更接近一点,因为它具有更高的精度。
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会将其移至最接近的值。
希望这能解释一下。
不是因为除法,问题是 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