java中的分裂

时间:2013-03-02 06:58:01

标签: java floating-point

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

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

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

为什么会这样?

4 个答案:

答案 0 :(得分:2)

这是任何事情中最常见的问题之一,所以我会在这里提出几点。

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

  2. 四舍五入的行为有点不可预测,因为计算机以二进制形式存储数字。因此,虽然19.7是终止小数,但相同的数字是二进制的重复小数 - 10011.10110011001100110011001100110011 ... ...因此您可以看到在任意点处舍入将产生无法从终止十进制表达式预测的行为。

答案 1 :(得分:0)

Mystical给出的链接是必读的,但它有点厚。请尝试this site以获得更适合初学者的版本。

tl; dr是浮点运算总是受到舍入的影响,并且由于具有更高的精度,双倍会比浮点数更圆。这有点像55舍入到最近的十个将是60,但四舍五入到最接近的百将是100。

在这种情况下,您无法在float或double中精确地表示十进制数0.197(或19.7,就此而言),因此每个都为您提供可以的数字表示哪个最接近该值。双精度可以更接近,因为它具有更高的精度。

答案 2 :(得分: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

答案 3 :(得分:0)

Java使用IEEE754浮点数来处理它的float和double。本标准设计为ise base 2 number,不能用于准确表示10。见http://en.wikipedia.org/wiki/IEEE_floating_point

以下不完全是标准,而是一个例子,只是为了让你知道为什么base 2浮点不适合其他基础。

base2  = base10
 0001  = 0001   -> from 0*8 + 0*4 + 0*2 + 1*1
 0010  = 0002   -> from 0*8 + 0*4 + 1*2 + 0*1
 0011  = 0003   -> from 0*8 + 0*4 + 1*2 + 1*1
 0100  = 0004   -> from 0*8 + 1*4 + 0*2 + 0*1
 0101  = 0005   -> from 0*8 + 1*4 + 0*2 + 1*1
                   8 = 2^3, 4 = 2^2, 2=2^1 and 1 = 2^0

Then
base2   = base10
 .0000 = .0000  -> from 0*1 + 0.5*0 + 0.25*0 + 0.125*0 + 0.0625*0
 .0001 = .0625  -> from 0*1 + 0.5*0 + 0.25*0 + 0.125*0 + 0.0625*0
 .0010 = .1250  -> from 0*1 + 0.5*0 + 0.25*0 + 0.125*0 + 0.0625*0
 .0011 = .1875  -> from 0*1 + 0.5*0 + 0.25*0 + 0.125*0 + 0.0625*0
 .0100 = .2500  -> from 0*1 + 0.5*0 + 0.25*0 + 0.125*0 + 0.0625*0
 .0101 = .3125  -> from 0*1 + 0.5*0 + 0.25*0 + 0.125*0 + 0.0625*0
 .0110 = .3750  -> from 0*1 + 0.5*0 + 0.25*0 + 0.125*0 + 0.0625*0
 .0111 = .4375  -> from 0*1 + 0.5*0 + 0.25*0 + 0.125*0 + 0.0625*0
 .1000 = .5000  -> from 0*1 + 0.5*0 + 0.25*0 + 0.125*0 + 0.0625*0
 .1001 = .5625  -> from 0*1 + 0.5*0 + 0.25*0 + 0.125*0 + 0.0625*0
 .1010 = .6250  -> from 0*1 + 0.5*0 + 0.25*0 + 0.125*0 + 0.0625*0
 .1011 = .6875  -> from 0*1 + 0.5*0 + 0.25*0 + 0.125*0 + 0.0625*0
 .1100 = .7500  -> from 0*1 + 0.5*0 + 0.25*0 + 0.125*0 + 0.0625*0
 .1101 = .8125  -> from 0*1 + 0.5*0 + 0.25*0 + 0.125*0 + 0.0625*0
 .1110 = .8700  -> from 0*1 + 0.5*0 + 0.25*0 + 0.125*0 + 0.0625*0
 .1111 = .9325  -> from 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 and 0.125 = 2^-3

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

由于实际标准使用了更多位以及使用数字移位技术。它可以真正代表比这个例子更多的数字,但限制仍然相同。因此,当你划分一些值并且结果不会落在其中一个上时...... JVM会将它移动到最接近的值。

希望这个解释。