Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Convert Long.MAX_VALUE to Float

Tags:

java

binary

bit

I am was having fun messing around by converting Integer to Float, Float to Long, Long to Int then I got confused by this behavior below.

When I convert a String s representing Long.MAX_VALUE (63 1s) I got a NumberFormatException which was expected. because Long is 64 bits and Integer is 32 bits so there are extra 31 1s. (This is my guess maybe is another reason please correct me if I am wrong)

However I am not sure why I did not get a NumberFormatException when converting Long to Float. Long again is 64 bits and Float is 32 bits just like Integer. I know bits are interpreted differently as Float(IEEE 754 floating-point "single format" bit layout) but what happened to all the other extra 31 bits? I am really lost here....

furthermore how do I get 9.223372E18 which is 1011111000000000000000000000000 bit string? where are those 0s from?

public static void main(String[] args){
    String s = String.valueOf(Long.MAX_VALUE); 
    print(s); //prints 9223372036854775807
    print(Long.toBinaryString(Long.MAX_VALUE)); //prints 111111111111111111111111111111111111111111111111111111111111111
    //Integer.valueOf(s) this throws NumberFormatException because Long is 64 bits and Integer is 32 so s is too large to be an Integer
    print(Float.valueOf(s)); //prints 9.223372E18 Why no NumberFormatException? and how did it result 9.223372E18?

    float f = Float.valueOf(s);
    int intBits = Float.floatToIntBits(f); 
    print(Integer.toBinaryString(intBits)); //1011111000000000000000000000000 How come? s was a String of 1s now there are 0s?
}

public static <T> void print(T arg){
    System.out.println(arg);
} 
like image 269
OLIVER.KOO Avatar asked Nov 07 '22 13:11

OLIVER.KOO


1 Answers

First, let's confirm for you that the conversion was correct.

Long.MAX_VALUE is 9223372036854775807 (19 digits). As you can see, the value is approximately what you printed: 9.223372E18.

The precision of a long is always 1. However, the precision of a float depends on the magnitude of the number.

In a IEEE single-precision floating point number, which float is, there are only 24 bits of precision in the mantissa, or "fraction" part of the storage. So the actual value represented by the float is an approximation to the actual value off Long.MAX_VALUE.

Float.floatToIntBits

As you've figured out, the Float.floatToIntBits method yields different bits than the original long bit representation.

Returns a representation of the specified floating-point value according to the IEEE 754 floating-point "single format" bit layout. Bit 31 (the bit that is selected by the mask 0x80000000) represents the sign of the floating-point number. Bits 30-23 (the bits that are selected by the mask 0x7f800000) represent the exponent. Bits 22-0 (the bits that are selected by the mask 0x007fffff) represent the significand (sometimes called the mantissa) of the floating-point number.

(snip)

Returns: the bits that represent the floating-point number.

This method doesn't convert it the value to an int, it only gives the bit representation of the float that happens to be stored in an int. The value represented by this int is not expected to be the same value as the float.

The conversion

Those zeroes are the mantissa of the floating point number. The actual conversion of long to float involves finding the sign for the most significant bit, finding the magnitude of the value to establish the exponent, and converting the rest of the value into the mantissa.

Because the precision of a float at the scale of Long.MAX_VALUE is limited, some precision is lost. The end result is that the float value is rounded up slightly. Because Long.MAX_VALUE is 1 short of a power of 2, the round up yields a power of 2, which shows up as all zeros in the mantissa.

You can see the precision of a floating-point value at the scale of a number with Math.ulp (unit in last place).

Math.ulp(f)

which yields

1.09951163E12

As you can see, the difference is quite large for a float for Long.MAX_VALUE. (The ulp for the corresponding double is 2048.0. Large, but much smaller than the ulp for float here.) But it's in line with what is expected for a value of almost 1019 -- about 7 digits of precision for a float.

like image 62
rgettman Avatar answered Nov 14 '22 22:11

rgettman