Subject: possible loss of precision
Posted By: hobby Post Date: 7/11/2008 11:52:38 PM
I am going through Ivor Horton's Java 2 JDK 5 Edition. I have version 6 on my machine. I'm doing Chapter 2 Exercise 1 where we initialize and declare a variable "byte number = 1;" We are to multiply it by 2 eight 8 times to go beyond the capacity of byte. I chose to use the statement "number = number * 2;" but got this error message when I did.

"Ch2Ex1.java:5: possible loss of precision
found   : int
required: byte
   number = number * 2;"
                   ^

I looked at the sample given and changed my statement to
"number *= 2;" and it compiled and it gave the expected error on the last output.

Is "number = number * 2;" and "number *= 2;" two different ways of saying the same thing? The whole purpose of the exercise is to loose precision. Why does the first way get an error message and not the second?


Reply By: Old Pedant Reply Date: 7/12/2008 1:45:13 AM
This is one of the oddities of Java.

FIrst of all "possible loss of precision" is *NOT* an error; it is just a warning.

You will note that the warning says "found: int, required: byte".

What it is saying is that the expression on the RIGHT side of the equals sign is an integer, but the variable on the left side is only a byte.  So, when you assign the integer to the byte, indeed you could "lose precision".  And you will, if the integer value is larger than 255.

WHY is the expression on the right side an integer???  When the variable number is just a byte??  Simply because the constant 2 is, by Java definition, an integer.  And any time you do mixed-type arithmetic, the values are "promoted" to the largest precision type.  [Actually, with Java it's a tad more complicated than that, but for this example that statement is true enough.]

Now, most of us were always taught that
     number *= 2;
is IDENTICAL to
     number = number * 2;

And it's true that the numeric result will be the same.  But the big difference is that Java *KNOWS* (for some weirdo reason...but you need a real Java afficianado and guru to tell you the gory details) that you are asking for a "byte only" operation.  And so no warning message.  And you only finally get an error when you really do exceed the capacity of the byte.

Again, there are some esoteric reasons why the behavior here changed between JDK 5 and JDK 6.  In some magic way, the version 6 behavior is "more correct."

If you care a lot, I think I could probably find the chapter and verse that explains the change; but honest, for 99.4% of all practical purposes, it doesn't matter.

And if you really really care a lot, then buy this book:
http://www.amazon.com/Java-TM-Puzzlers-Pitfalls-Corner/dp/032133678X/ref=pd_bbs_sr_1?ie=UTF8&s=books&qid=1215844842&sr=8-1
The book explains not only this point but dozens of other tricks and edge cases.  And convinces you that language designers must all be just a little crazy.  (Having designed a couple in my own time, I can attest that the latter is definitely true.)
Reply By: hobby Reply Date: 7/12/2008 8:54:10 PM
Thanks for your response. Just a note "First of all "possible
loss of precision" is *NOT* an error; it is just a warning."
that this warning does not let you compile. With in us is a
standard of perfection that we fail to measure up to, it's no surprise that our computer systems fail in the same way. In the future if I see this warning I'll know to change the code. I appreciate having someone online to talk this over with.

Reply By: Old Pedant Reply Date: 7/13/2008 10:48:16 PM
Huh...another change with JDK 6, I guess.  "Possible" was always a warning, as I remember it.  

Then answer, of course, is to do
    byteVariable = (byte) (2 * byteVariable);
casting the integer result to byte.

But what a pain.  Now you make me almost want to go look that oddity up in that "Puzzler" book (I remember it being in there) to see the rationale.

Reply By: hobby Reply Date: 7/20/2008 10:51:22 PM
I have all ready declared my variable as byte, and number = (byte)(number * 2) compiles OK. I was thinking "number" is already a byte and 2 might be the problem so I tried number = number * (byte)2; but got the same error message

Ch2Ex1.java:7: possible loss of precision
found   : int
required: byte
   number = number * (byte) 2;

Reply By: Old Pedant Reply Date: 7/21/2008 4:36:26 PM
Java never does arithmetic in anything smaller than integer precision.

http://java.sun.com/docs/books/jls/third_edition/html/typesValues.html#4.2.2

So casting the 2 to a byte does nothing to change that.

You would need to cast the *result* of the operation to byte.

Thus:

     number = (byte)(number * 2);

Note that section 5.2 of those same docs certainly says you need that cast there to prevent a compile time error.  (You can then still get a runtime error, of course, but that's a different matter.)

Ahhh...and here's where the docs clearly spell out why
     byte number = 1;
     number *= 2;
is different than
     byte number = 1;
     number = number * 2;

http://java.sun.com/docs/books/jls/third_edition/html/expressions.html#15.26.2

The very first sentence says it all:
A compound assignment expression of the form E1 op= E2 is equivalent to E1 = (T)((E1) op (E2)), where T is the type of E1, except that E1 is evaluated only once.

So
     byte number = 1;
     number *= 2;
truly *IS* equivalent to
     byte number = 1;
     number = (byte) (number * 2);
!!!!!!!!

See, not so esoteric, after all!

It is that implicit cast *OF THE RESULT* that the *= operator produces that is missing in the other case.


    
Reply By: hobby Reply Date: 7/23/2008 2:42:39 PM
Thanks for the documentation links. Doing this kind of research is something I would like to learn. I looked up the word esoteric and it is a mysterious specialized knowledge amongst an inner circle of people. From what I understand, there is a cutting edge group of people developing the Java software. There is two types of  knowledge discernment and wisdom. Discernment is knowing what a situation is and wisdom is knowing what to do about it. For example you discerned my error message and recommended casting the right side of the equation to (byte). This recommendation is wisdom, but this wisdom is based on our knowledge of the situation. Our knowledge is a thin spider web that  stretches over reality. The mystery is the imperfection or incompleteness of that knowledge. Admitting the mystery is mental humbleness and I think is a good thing.


Go to topic 72948

Return to index page 1