1
votes

Since all Java floating-point numbers, which are floats and doubles, are internally represented as bits, I want to find an efficient algorithm to convert a String representing the bits of that float or double and convert it into its corresponding floating-point number - I couldn't find a built-in library function for it so I resorted to writing it by myself.

A binary String of length 32 represents a float, where as a binary String of length 64 will be converted to a double. All floats can be converted to doubles without loss of accuracy. Spaces are ignored.

Examples

  • "0 10000000 10010010000111111011011" becomes 3.141592 as a float.
  • "1 11111111 00000000000000000000000" becomes -infinity.
  • "0 11111111 10010010000111111011011" becomes a float NaN.
  • "1 10000000000 0101101111110000101010001011000101000101011101101001"
    becomes a double value closest to -e, which is 2.71828182845904509079559829843

So far I have this mass of a code:

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

Though my code works as of now, what is the neatest or fastest method to convert a IEEE-754 binary representation String to its float or double, in terms of speed and amount of code? The most efficient method with a good explanation of its efficiency and expertise is preferred.

2
This question is not about converting a "binary" decimal into a float. - Ṃųỻịgǻňạcểơửṩ
If you're looking to improve code that already works, you should probably try codereview.stackexchange.com - VeeArr
@StephenC how about the case for doubles? Is the simplified code more efficient? - Ṃųỻịgǻňạcểơửṩ

2 Answers

4
votes

This approach is probably more efficient. It is certainly simpler and more maintainable.

  1. Remove spaces from string
  2. Validate string length ...
  3. Convert binary string to int
  4. Call Float.intBitsToFloat(int) to convert to an float.

For doubles, use long and the equivalent Double method.


Is the simplified code more efficient?

The only way to be sure is to benchmark it. But based on what your code is doing, I believe so.

0
votes

From @StephenC, the improved code to convert the IEEE-754 binary representation to its corresponding floating-point value takes up just one line:

return Float.intBitsToFloat(Integer.parseUnsignedInt(binString, 2));
  • Integer.parseUnsignedInt(binString, 2) converts the unsigned int in binary digits from range 0 to 232-1 to the int representation. The parseInt(...) does not work because parseInt involves an explicit sign in its binString, and if it represents a negative int, a leading hyphen is required instead of a value that is 231 or greater. Similarly, Long.parseUnsignedLong(binString, 2) appiles for the 64-bit case.

  • Float.intBitsToFloat(int n) represents the float value with the same bits internally stored as the int value n. Similarly, Double.longBitsToDouble(long n) works for the 64-bit case.

  • Using "method composition", this line first converts the (unsigned) binary string into its corresponding int, and then converts it into the floating-point value with the same stored bits.

The final code would be

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