如何在Java中将IEEE-754二进制表示形式的String转换为float或double?

时间:2018-07-16 22:48:40

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

由于所有Java浮点数( floats doubles )在内部都表示为位,因此我想找到一种效率算法,将代表该 float double 的位的字符串转换为对应的浮点数-我找不到内置的库函数,所以我只能自己编写。

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

示例

  • "0 10000000 10010010000111111011011"成为<{> float 的3.141592
  • "1 11111111 00000000000000000000000"成为-infinity
  • "0 11111111 10010010000111111011011"成为 float NaN
  • "1 10000000000 0101101111110000101010001011000101000101011101101001"
    成为最接近 -e double 值,即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吗?最好使用最能说明其效率和专业知识的方法。

2 个答案:

答案 0 :(得分:3)

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

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

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


  

简化代码更有效吗?

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

答案 1 :(得分:0)

从@StephenC 起,用于将IEEE-754二进制表示形式转换为其对应的浮点值的改进代码仅占用一行:

return Float.intBitsToFloat(Integer.parseUnsignedInt(binString, 2));
  • Integer.parseUnsignedInt(binString, 2)将范围从0到2 32 -1的二进制数字 unsigned int转换为int表示形式。 parseInt(...)不起作用,因为parseInt在其binString中包含显式符号,并且如果它表示负整数,则需要前导连字符而不是2 31 或更高。同样,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");
    }
}