Java:为什么Hex值对于相同的浮点值是不同的?

时间:2013-10-26 14:44:26

标签: floating-point double hex

所以我有BigDecimal保持值0.99并且我调用:

  • Float.toHexString(rationalNumber.floatValue())我得到 0x1.fae148p-1
  • Double.toHexString(rationalNumber.doubleValue())我得到 0x1.fae147ae147aep-1

我在思考,因为我们代表一个像0.99这样的小数字,我们应该得到相同的十六进制值,无论如何。同意?

代码(测试失败):

@Test public void testDelta() {
    BigDecimal rationalNumber = new BigDecimal("0.99").setScale(2,BigDecimal.ROUND_DOWN);

    String hexFromFloat = Float.toHexString(rationalNumber.floatValue());
    String hexFromDouble = Double.toHexString(rationalNumber.doubleValue());

    String hexFromFloatMsg = rationalNumber.floatValue() + " = " + hexFromFloat;
    String hexFromDoubleMsg = rationalNumber.doubleValue() + " = " + hexFromDouble;

    Assert.assertEquals(hexFromFloatMsg + ", " + hexFromDoubleMsg, hexFromDouble, hexFromFloat);
}

输出:

org.junit.ComparisonFailure: 0.99 = 0x1.fae148p-1, 0.99 = 0x1.fae147ae147aep-1 
Expected :0x1.fae147ae147aep-1
Actual   :0x1.fae148p-1

2 个答案:

答案 0 :(得分:2)

这两个操作之间存在差异:

rationalNumber.floatValue()
rationalNumber.doubleValue()

每个都将BigDecimal的.99转换为浮点值。在十六进制浮点数(带有十进制指数,幂为2)时,。99为0x1.fae147ae147ae147 ... p-1。当它转换为float时,只能存储有效数字(小数部分)的24位,因为这是float类型对有效数字的所有位。 (显式存储23位;其中一位是编码的其他部分隐含的。)因此,转换必须将.99的精确值四舍五入为24位。这产生1.fae148p-1。如果以二进制形式编写1.fae147ae147ae147 ...并计算24位,则可以看到舍入发生的位置。这里它们的前24位为粗体: 1.11111010111000010100011 110101110000101000111 ... p-1。舍入时,我们查看被删除的位,看它们是保留的最低位的一半以上(删除的第一位是1,还有超过1位),并决定向上舍入。因此舍入产生1.11111010111000010100100p-1。在十六进制中,即1.fae148p-1。

当.99转换为double时,可以存储53位有效数字。所以它在不同的位置四舍五入。这会产生0x1.fae147ae147aep-1。

这两个值是不同的,直接比较它们会报告它们是不同的,将它们从浮点格式转换为十六进制数字会产生不同的结果。

答案 1 :(得分:-1)

  

因为我们代表一个像0.99这样的小数字,所以我们应该得到相同的十六进制值。同意?

这是十进制的小精度,但正如您所看到的,其十六进制表示重复(0x1.f(ae147)*)。它正好被表示,但它不能完全打印