Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does Java implicitly (without cast) convert a `long` to a `float`?

Tags:

java

casting

Every time I think I understand about casting and conversions, I find another strange behavior.

long l = 123456789L; float f = l; System.out.println(f);  // outputs 1.23456792E8 

Given that a long has greater bit-depth than a float, I would expect that an explicit cast would be required in order for this to compile. And not surprisingly, we see that we have lost precision in the result.

Why is a cast not required here?

like image 690
Eric Wilson Avatar asked Aug 18 '09 13:08

Eric Wilson


People also ask

Can we type cast long to float?

Long class has the following methods for converting long type value to other primitive types. byte byteValue() returns the value of this Long as a byte. double doubleValue() returns the value of this Long as a double. float floatValue() returns the value of this Long as a float.

Can long be stored in float?

From float to long you could lose all behind the floating point so there will be no implicit cast because normally you do not want to lose this information. You may well lose information going from long to float . That's the point of the question.

Which primitive type conversion is permitted implicitly without using casting?

Casting between primitive types enables you to convert the value of one type to another primitive type is called Primitive Type Casting. This is most commonly occurs with the numeric data types . But boolean primitive type can never be used in a cast.

Does Java implicitly cast?

Types of Casting in Java Two types of casting are possible in Java are as follows: Implicit type casting (also known as automatic type conversion)


2 Answers

The same question could be asked of long to double - both conversions may lose information.

Section 5.1.2 of the Java Language Specification says:

Widening primitive conversions do not lose information about the overall magnitude of a numeric value. Indeed, conversions widening from an integral type to another integral type do not lose any information at all; the numeric value is preserved exactly. Conversions widening from float to double in strictfp expressions also preserve the numeric value exactly; however, such conversions that are not strictfp may lose information about the overall magnitude of the converted value.

Conversion of an int or a long value to float, or of a long value to double, may result in loss of precision-that is, the result may lose some of the least significant bits of the value. In this case, the resulting floating-point value will be a correctly rounded version of the integer value, using IEEE 754 round-to-nearest mode (§4.2.4).

In other words even though you may lose information, you know that the value will still be in the overall range of the target type.

The choice could certainly have been made to require all implicit conversions to lose no information at all - so int and long to float would have been explicit and long to double would have been explicit. (int to double is okay; a double has enough precision to accurately represent all int values.)

In some cases that would have been useful - in some cases not. Language design is about compromise; you can't win 'em all. I'm not sure what decision I'd have made...

like image 172
Jon Skeet Avatar answered Oct 19 '22 09:10

Jon Skeet


The Java Language Specification, Chapter 5: Conversion and Promotion addresses this issue:

5.1.2 Widening Primitive Conversion

The following 19 specific conversions on primitive types are called the widening primitive conversions:

  • byte to short, int, long, float, or double
  • short to int, long, float, or double
  • char to int, long, float, or double
  • int to long, float, or double
  • long to float or double
  • float to double

Widening primitive conversions do not lose information about the overall magnitude of a numeric value.

...

Conversion of an int or a long value to float, or of a long value to double, may result in loss of precision-that is, the result may lose some of the least significant bits of the value. In this case, the resulting floating-point value will be a correctly rounded version of the integer value

To put it another way, the JLS distinguishes between a loss of magnitude and a loss of precision.

int to byte for example is a (potential) loss of magnitude because you can't store 500 in a byte.

long to float is a potential loss of precision but not magnitude because the value range for floats is larger than that for longs.

So the rule is:

  • Loss of magnitude: explicit cast required;
  • Loss of precision: no cast required.

Subtle? Sure. But I hope that clears that up.

like image 25
cletus Avatar answered Oct 19 '22 10:10

cletus