【问题标题】:Hexadecimal -> Float Conversion Inaccurate十六进制 -> 浮点转换不准确
【发布时间】:2016-09-13 08:53:57
【问题描述】:

我正在使用以下代码将十六进制 String 转换为浮点 String

private static String removeScientificNotation(float value)
{
    return new BigDecimal(Float.toString(value)).toPlainString();
}

/**
 * Converts a hexadecimal value to its single precision floating point representation
 *
 * @param hexadecimal The <code>hexadecimal</code> to convert
 * @return The converted value
 */
public static String hexadecimalToFloatingPoint(String hexadecimal)
{
    Long longBits = Long.parseLong(hexadecimal, 16);
    Float floatValue = Float.intBitsToFloat(longBits.intValue());

    return removeScientificNotation(floatValue);
}

为了对此进行测试,我编写了以下JUnit 测试:

public class TestConversions
{
    @Test
    public void testConversions()
    {
        String floatValue = Conversions.hexadecimalToFloatingPoint("40000000");
        Assert.assertEquals(floatValue, "2.0");
        floatValue = Conversions.hexadecimalToFloatingPoint("50000000");
        Assert.assertEquals(floatValue, "8589934592");
        floatValue = Conversions.hexadecimalToFloatingPoint("C0000000");
        Assert.assertEquals(floatValue, "-2.0");
    }
}

但是,第二个断言失败。根据this one等各种在线转换器,50000000应转换为8589934592,但Java返回8589934600

org.junit.ComparisonFailure: 
Expected :8589934600
Actual   :8589934592

现在哪个结果是正确的?如果Java错了,我该如何纠正呢?

【问题讨论】:

  • 我怀疑你所看到的是 float 应该只依赖 7 位有效数字的精度...(尝试返回 float 而不是 String,并比较你的结果到 8589934600f)
  • 请注意,最接近 8589934600 的精确浮点值是 8589934592。
  • 这就是为什么您不应该与浮点数进行精确比较的原因。对于单元测试中的断言,有Assert#equals(floatA, floatB, delta)
  • 欺负请找我的答案

标签: java string floating-point bigdecimal data-conversion


【解决方案1】:

您可以通过直接将浮点值传递给 BigDecimal 构造函数来实现这一点,如下所示。问题的原因是Float.toString(value)(因为此方法是对FloatingDecimaltoJavaFormatString 进行内部调用,它似乎对值进行了一些舍入)所以不需要使用 Float.toString 而只是传递你的实际浮点值。

    String myString = "50000000";
    Long i = Long.parseLong(myString, 16);
    Float f = Float.intBitsToFloat(i.intValue());
    String finalString= new BigDecimal(f).toPlainString();
    System.out.println("final value  "+finalString);

所以只需改变你的方法,如下所示。

private static String removeScientificNotation(float value)
{
    return new BigDecimal(value).toPlainString();
}

【讨论】:

  • Float.toString(value) 的具体问题在于,它会从将转换为value 的小数范围中选择有效数字最少的那个,而不是确切的值。适合展示,不适合这个目的。
  • 只是附带说明,没有必要使用LongFloat 来代替实际的longfloat 类型。在Long 上调用intValue() 只会混淆从longint 发生的类型转换。除此之外,它只包含了不必要的装箱和拆箱。
猜你喜欢
  • 2014-03-01
  • 2016-06-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-12-08
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多