【问题标题】:How can I convert an IEEE-754 binary representation String to a float or double in Java?如何在 Java 中将 IEEE-754 二进制表示字符串转换为浮点数或双精度数?
【发布时间】:2018-07-16 22:48:39
【问题描述】:

由于所有 Java 浮点数,即 floatsdoubles,在内部都表示为位,我想找到一个 高效的算法转换表示该 floatdouble 位的字符串并将其转换为其相应的 浮点数 - 我找不到一个内置的库函数,所以我只好自己写了。

长度为 32 的二进制字符串表示 float,其中长度为 64 的二进制字符串将转换为 double。所有 floats 都可以转换为 doubles 而不会损失准确性。空格被忽略。

示例

  • "0 10000000 10010010000111111011011" 变为 3.141592 作为 float
  • "1 11111111 00000000000000000000000" 变为 -infinity
  • "0 11111111 10010010000111111011011" 变为 float NaN
  • "1 10000000000 0101101111110000101010001011000101000101011101101001"
    成为最接近-edouble值,即2.71828182845904509079559829843

到目前为止,我有这么多代码:

public static double ieee(String binString) throws Exception {
    binString = binString.replace(" ", "");
    if (binString.length() == 32) {
        String exponentB = binString.substring(1, 9);
        String mantissaB = binString.substring(9, 32);
        int sgn = binString.charAt(0) == '0' ? 1 : -1;
        int exponent = Integer.parseInt(exponentB, 2) - 127; // Biased by 127
        double mantissa = 1 + Integer.parseInt(mantissaB, 2) / Math.pow(2, 23);

        if (exponent == 128 && mantissa == 1)
            return sgn == 1 ? Double.POSITIVE_INFINITY : Double.NEGATIVE_INFINITY;
        if (exponent == 128 && mantissa != 0)
            return Double.NaN;
        if (exponent == -127)
            return sgn*Math.pow(2,-126)*(mantissa - 1);
        return sgn*Math.pow(2, exponent)*mantissa;
    }
    else if (binString.length() == 64) {
        String exponentB = binString.substring(1, 12);
        String mantissaB = binString.substring(12, 64);
        int sgn = binString.charAt(0) == '0' ? 1 : -1;
        int exponent = Integer.parseInt(exponentB, 2) - 1023; // Biased by 1023
        double mantissa = 1 + Long.parseLong(mantissaB, 2) / Math.pow(2, 52);

        if (exponent == 1024 && mantissa == 1)
            return sgn == 1 ? Double.POSITIVE_INFINITY : Double.NEGATIVE_INFINITY;
        if (exponent == 1024 && mantissa != 0)
            return Double.NaN;
        if (exponent == -1023)
            return sgn*Math.pow(2,-1022)*(mantissa - 1);
        return sgn*Math.pow(2, exponent)*mantissa;
    }
    else {
        throw new Exception("Does not represent internal bits of a floating-point number");
    }
}

虽然我的代码目前可以工作,但就速度和代码量而言,将 IEEE-754 二进制表示字符串转换为其floatdouble 的最简洁或最快的方法是什么?最好是最有效的方法,并对其效率和专业知识有很好的解释。

【问题讨论】:

  • 这个问题不是关于将“二进制”十进制转换为浮点数。
  • 如果你想改进已经可以运行的代码,你应该试试codereview.stackexchange.com
  • @StephenC 双打的情况如何?简化的代码效率更高吗?

标签: java string floating-point ieee-754 string-parsing


【解决方案1】:

这种方法可能更有效。它当然更简单,更易于维护。

  1. 从字符串中删除空格
  2. 验证字符串长度...
  3. 将二进制字符串转换为int
  4. 致电Float.intBitsToFloat(int) 转换为float

对于双打,使用long 和等效的Double 方法。


简化后的代码效率更高吗?

唯一确定的方法是对其进行基准测试。但根据你的代码在做什么,我相信是的。

【讨论】:

  • 基准测试时,您的方法肯定更快吗?我的“低效”算法看起来像是一种“更天真”的方法来转换 ieee754 浮点表示。
  • 1) 随意编写自己的基准测试 :-) 2) 是的。我的方法避免了所有那些乱七八糟的东西。在后台intBitsToFloat 将是一个简单的任务。
【解决方案2】:

来自@StephenC​​trong>,将 IEEE-754 二进制表示转换为其对应的浮点值的改进代码只占用一行代码:

return Float.intBitsToFloat(Integer.parseUnsignedInt(binString, 2));
  • Integer.parseUnsignedInt(binString, 2) 将二进制数字中的 unsigned int 从 0 到 232-1 转换为 int 表示。 parseInt(...) 不起作用,因为 parseInt 在其 binString 中包含显式符号,并且如果它表示负整数,则需要前导连字符而不是值 231 或更大。同样,Long.parseUnsignedLong(binString, 2) 适用于 64 位情况。

  • Float.intBitsToFloat(int n) 表示浮点值,其内部存储的位与 int 值 n 相同。同样,Double.longBitsToDouble(long n) 适用于 64 位情况。

  • 使用“方法组合”,此行首先将(无符号)二进制字符串转换为其对应的int,然后将其转换为具有相同存储位的浮点值。

最终的代码是

public static double ieeeToFloat(String binString) throws Exception {
    binString = binString.replace(" ", "");
    /* 32-bit */
    if (binString.length() == 32) {
        return Float.intBitsToFloat(Integer.parseUnsignedInt(binString, 2));
    }
    /* 64-bit */
    else if (binString.length() == 64) {
        return Double.longBitsToDouble(Long.parseUnsignedLong(binString, 2));
    }
    /* An exception thrown for mismatched strings */
    else {
        throw new Exception("Does not represent internal bits of a floating-point number");
    }
}

【讨论】:

    猜你喜欢
    • 2011-09-18
    • 1970-01-01
    • 1970-01-01
    • 2011-03-07
    • 2014-06-18
    • 1970-01-01
    • 1970-01-01
    • 2021-04-01
    • 1970-01-01
    相关资源
    最近更新 更多