JamieP
JamieP

Reputation: 1774

Double to Int without lossy precision

The following declaration gives me a compile-time error "Error:(19, 13) java: incompatible types: possible lossy conversion from double to int"

int i1 = 10.0;

// Error:(19, 14) java: incompatible types: possible lossy conversion from double to int

Question 1

I understand the error but can the compiler not infer - in this particular case - that there will be no loss of precision?

Question 2

If I explicitly convert the double to an int then it compiles fine (not even a warning) even though I am definitely losing precision in this example

int i2 = (int)9999999999999.999999999;

If I can't compile the first case - where no loss occurs - then why does this second example with the explicit conversion not even generate a compiler warning?

Upvotes: 3

Views: 386

Answers (4)

Andreas
Andreas

Reputation: 159086

The assignment of a double value to an int variable would require a narrowing conversion, even if the value is a compile-time constant, and hence requires an explicit cast.

Except that an int (or short or char) constant value can be assigned to a byte, short, or char variable without casting, if the constant actually fits in the variables value range, as explicitly documented in the Java Language Specification, section 5.2. Assignment Contexts:

Assignment contexts allow the value of an expression to be assigned (§15.26) to a variable; the type of the expression must be converted to the type of the variable.

Assignment contexts allow the use of one of the following:

  • an identity conversion (§5.1.1)

  • a widening primitive conversion (§5.1.2)

  • a widening reference conversion (§5.1.5)

  • a boxing conversion (§5.1.7) optionally followed by a widening reference conversion

  • an unboxing conversion (§5.1.8) optionally followed by a widening primitive conversion.

If, after the conversions listed above have been applied, the resulting type is a raw type (§4.8), an unchecked conversion (§5.1.9) may then be applied.

In addition, if the expression is a constant expression (§15.28) of type byte, short, char, or int:

  • A narrowing primitive conversion may be used if the type of the variable is byte, short, or char, and the value of the constant expression is representable in the type of the variable.

  • A narrowing primitive conversion followed by a boxing conversion may be used if the type of the variable is:

    • Byte and the value of the constant expression is representable in the type byte.

    • Short and the value of the constant expression is representable in the type short.

    • Character and the value of the constant expression is representable in the type char.

Upvotes: 2

Eugene
Eugene

Reputation: 120848

Interesting question

In theory this could be possible, well javac does not complain when doing:

short s = 12;

Even if 12 here is a compile time constant of type int, so it can deduce that no precision is lost. I guess this is what the compiler team thought would be most appropriate.

Well when you cast is a different story, it's like saying "trust me, I know what I'm doing", even if you loose precision.

Upvotes: 1

Sweeper
Sweeper

Reputation: 271040

Answer to question 1

There is a loss of precision according to the compiler, because the compiler only sees that you have an int variable on the left and a double value on the right. The compiler is not so smart as to figure out that 10.0 will not lose precision when converted to an int.

The compiler could in theory be built to allow that statement to compile, but there is no real benefit in doing so. Almost no one writes int x = 10.0.

Answer to question 2

Indeed, there is a loss of precision, but why did the compiler not complain? Because you used a cast. You wrote (int). This is you showing the compiler that you know what you're doing. By writing a cast, you are telling it that you are aware that there is a possible loss of precision.

Upvotes: 1

Mureinik
Mureinik

Reputation: 311163

In theory, a compiler could infer that the specific example in #1 wouldn't actually loose precision based on the literal's value, but as you've seen - it doesn't.

The explicit cast signals to the compiler that you are aware of the situation an handling it, so the code actually compiles. Most IDEs, however, could be configured to emit a warning in such a situation too.

Upvotes: 2

Related Questions