5

昨天有人问了这个问题。我知道 java 解释3.0为 adouble3fa float,并且doubles具有 64 位精度和floats32 位精度。如果有人问我,我会给出与给出的答案相似的答案;但是,我想提供经验证据,清楚地表明java商店3.03f不同之处。

这是我尝试过的,但收效甚微:

    System.out.println("Double: " + Double.toHexString(d)); //prints 0x1.8p1
    System.out.println("Float: " + Float.toHexString(f)); //prints 0x1.8p1

    System.out.println("Double: " + new Double(d).byteValue()); //prints 3
    System.out.println("Float: " + new Float(f).byteValue());  //prints 3 

    Long l = Double.doubleToLongBits(d);
    Integer i = Float.floatToIntBits(f);

    System.out.println("Double (long bits): " + l); //prints 4613937818241073152
    System.out.println("Float (int bits): " + i); //prints 1077936128

这些是不同的,但这是因为floats使用单格式(8 位偏置指数)和doubles双格式(11 位偏置指数)。有关详细信息,请参阅IEEE 算术。我将两者都转换为它们的二进制表示,但又没有得到任何地方:

    System.out.println("Long-toBinary: " + Long.toBinaryString(l)); 
    //prints 100000000001000000000000000000000000000000000000000000000000000
    System.out.println("Integer-toBinary: " + Integer.toBinaryString(i)); 
    //prints 1000000010000000000000000000000 

虽然在 中还有更多0's,但Long.toBinaryString(l)乘以加法0's不会改变结果(开头 1 的不同位置是由于 8 位与 11 位的偏置指数问题)。所以,我仍然没有经验证据来说明为什么下面问题的乘法会产生两个不同的答案。

  97346822*3f, result is 2.9204048E8,

然而

 97346822*3.0 gives me 2.92040466E8.

3f并且3.0必须不同才能使结果不同,但我想不出任何表明它们实际上是的东西。再次,我理解这3f被解释为 afloat3.0a double,请不要仅仅回答这个问题。

编辑:
为了澄清,我试图隔离 3.03f表明它们确实不同。

4

1 回答 1

5

这个答案也与这个有关。

3.0 和 3f 本身:

它们的值是相等的。我们的值中有一些指数和 2 个连续的指数。这同样代表 3.0 和 3f。现在的问题是浮点乘法。每个浮点乘法都发生在处理器硬件上,并且所有乘法都发生在浮点值本身内,具有相同的精度(双精度/浮点)。虽然值3.03f相等,但它们在乘法如何发生方面并不相等。这在我的系统上无关紧要,strictfp因为我的 CPU 完全符合 IEEE 754 标准。

其他发现

此代码可以提示您:

 BigDecimal val1=new BigDecimal(97346822*3f);
 BigDecimal val2=new BigDecimal(97346822*3.0);
 System.out.println(val1.subtract(val2, MathContext.UNLIMITED).toEngineeringString());
 System.out.println(val1.equals(val2));
 System.out.println(val1.compareTo(val2));

这会根据我们的值创建两个 BigDecimal。

第一个输出是作为工程字符串的差异,14not 0

第二个输出false显示 BigDecimal 没有发现它们具有相同的价值和精度。

第三个输出给出1. 因此,在 BigDecimal 的上下文中,值 1 大于值 2。

打印两个precision(结果表明它们的精度均为 9。

不同的浮点/双精度值,如果没有重复的小数,就不能用二进制表示

让我们用不同的值运行相同的代码:

BigDecimal val1=new BigDecimal(3.1f);
BigDecimal val2=new BigDecimal(3.1);
System.out.println(val1.subtract(val2, MathContext.UNLIMITED).toEngineeringString()); //-95.367431729442841970012523233890533447265625E-9
System.out.println(val1.equals(val2)); //false
System.out.println(val1.compareTo(val2)); // -1
System.out.println(val1.precision()); // 22
System.out.println(val2.precision()); // 52

我们可以看到,浮点数/双精度值中相同的十进制字面值表示可证明不同的值。在这种情况下,十进制 3.1 不能完全适合二进制十进制。以 10 为底的小数和小数 2/3 也会产生类似的效果。而 2/3 将被写为:

  _
0.6

我们会将其写为 0.66666667 的有限长度。如果我们有更长的长度,它将类似于 0.6666666666666667。

从字面上看,0.66666667!=0.6666666666666667。

于 2013-07-26T14:10:20.627 回答