Java:为什么Hex值在同一个浮点值上不同? [英] Java: Why the Hex value is different for same floating-point value?

查看:165
本文介绍了Java:为什么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 
预期:0x1.fae147ae147aep-1
实际:0x1。 fae148p-1


解决方案

差异发生在这两个操作中:

  rationalNumber.floatValue()
rationalNumber.doubleValue()
/ pre>

每个都将$ code> BigDecimal 的值为.99转换为浮点数。在十六进制浮点数(二进制数的十进制指数)中,.99为0x1.fae147ae147ae147 ... p-1。当这个转换为 float 时,只有24位的有效位数(分数部分)可以存储,因为这是所有的位$ float type有一个有效数。 (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。



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


So I have BigDecimal holding value 0.99 and I invoke:

  • Float.toHexString(rationalNumber.floatValue()) I get 0x1.fae148p-1
  • Double.toHexString(rationalNumber.doubleValue()) I get 0x1.fae147ae147aep-1

I'm thinking since we are representing a small number like 0.99 we should get the same hex value regardless. Agree?

Code (failing test):

@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);
}

Output:

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

解决方案

The difference occurs in these two operations:

rationalNumber.floatValue()
rationalNumber.doubleValue()

Each of these converts a BigDecimal value of .99 to floating-point. In hexadecimal floating-point (with a decimal exponent for a power of two), .99 is 0x1.fae147ae147ae147…p-1. When this is converted to float, only 24 bits of the significand (fraction part) can be stored, because that is all the bits the float type has for a significand. (23 bits are stored explicitly; one is implicit from other parts of the encoding.) So, the conversion must round the exact value of .99 to something that fits in 24 bits. This produces 1.fae148p-1. If you write 1.fae147ae147ae147… in binary and count out 24 bits, you can see where the rounding occurs. Here they are with the first 24 bits in bold: 1.11111010111000010100011110101110000101000111…p-1. When rounding, we look at the bits being removed, see that they are more than half the lowest bit being kept (the first bit being removed is 1, and there are additional 1 bits beyond it), and decide to round up. So rounding produces 1.11111010111000010100100p-1. In hexadecimal, that is 1.fae148p-1.

When .99 is converted to double, 53 bits of the significand can be stored. So it is rounded at a different position. This produces 0x1.fae147ae147aep-1.

The two values are different, comparing them directly would report they are different, and converting them from the floating-point format to hexadecimal numerals produces different results.

这篇关于Java:为什么Hex值在同一个浮点值上不同?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆