简体   繁体   中英

How does long value fit in float data type in Java without loss of precision

How does long value fit in float data type in Java without loss of precision. Because if there is loss of precision then the following snippet should have produced

long lMax = Long.MAX_VALUE;
float f = lMax;
System.out.println(lMax == f);

Output 
true

The problem is, that for comparison of long and float the long value is being cast to float , and the same loss of precision occurred as in the assignment...

If you want to "detect" loss of precision, try using BigDecimal s, something like this:

System.out.println(new BigDecimal(lMax).compareTo(new Bigdecimal(f)));

I know that the constructor BigDecimal(double) will get the float cast to double but there is no precision lost...

Edit

For most people long seems to have more "precision" than float . However float has a range of +/-10^38 , which is much larger than long 's...

Tests

long lMax = Long.MAX_VALUE;
float f = lMax;
System.out.println( lMax == f );
System.out.println( new BigDecimal( lMax ).compareTo( new BigDecimal( f ) ) );
System.out.println( ( (Float) f ).longValue() == lMax );
System.out.println( ( (Long) lMax ).floatValue() == f );
System.out.printf( "%d, %d%n", ( (Float) f ).longValue(), lMax );

f = --lMax;
System.out.println( lMax == f );
System.out.println( new BigDecimal( lMax ).compareTo( new BigDecimal( f ) ) );
System.out.println( ( (Float) f ).longValue() == lMax );
System.out.println( ( (Long) lMax ).floatValue() == f );
System.out.printf( "%d, %d%n", ( (Float) f ).longValue(), lMax );

Outputs:

true
-1
true
true
9223372036854775807, 9223372036854775807
true
-1
false
true
9223372036854775807, 9223372036854775806

The Binary Numeric Promotion rules in the Java language Specification are key to understanding the behavior of the code snippet in the question. In particular "Otherwise, if either operand is of type float, the other is converted to float."

In the lMax == f comparison, lMax is converted to float exactly as was done by the float f = lMax assignment. If you take the same input value, do the same transformation on it twice, and compare the results they will be equal regardless of whether the transformation changed the value or not.

If you want a good demonstration of the precision loss, try this little script when getting system time in milliseconds and converting from long to float:

class Scratch {
    public static void main(String[] args) throws InterruptedException {

        float currentF;
        long currentL;
        float lastNewF = 0;
        long lastL = System.currentTimeMillis();
        long diff;

        while (true) {
            currentL = System.currentTimeMillis();
            currentF = (float) currentL;
            if (currentF != lastNewF) {
                // we finally got a new "different" float value
                lastNewF = currentF;
                diff = currentL - lastL;
                lastL = currentL;
                System.out.println(diff + " milliseconds since we got a new time as float");
            }
            Thread.sleep(250);
        }
    }
}

You can see from the output that you are sometimes losing up to 2 minutes of precision:

0 milliseconds since we got a new time as float
46964 milliseconds since we got a new time as float
131054 milliseconds since we got a new time as float
131093 milliseconds since we got a new time as float
131077 milliseconds since we got a new time as float

The value of lMax =9223372036854775807; // It might be different in your JVM.

Value of f = 9.223372E18

Now when you compare lMax == f , first f is converted to long and then comparison happens. After converting into long, f value is same as lMax.

Even same apply for following code.

long lMax = Long.MAX_VALUE; // value is 9223372036854775807
float f =lMax;
float f2 = 9223372036854775807.5f;
System.out.println(lMax == f);
System.out.println(lMax == f2);

Output

true
true

Here f2 is losing decimal value when compared to long. And long value of f2 is same as lMax.

lMax is a long number. When u assign it to a float it will lose the precision.

float f = lMax;

When you compare a long to a float, internally either long is converted to a float or float is converted to a long. your code

lMax == f

will be similar to

((Float)f).longValue() == lMax

which is 9.223372E18 == 9.223372E18 true

or

((Long)lMax).floatValue() == f

which is 9223372036854775807 == 9223372036854775807 true

in either way the answer is true.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM