Page 3 of 4
Widening and Narrowing
When it comes to data types there are two possible types of assignment - widening and narrowing.
A widening assignment causes no problem because the variable on the left is "bigger" than what is being computed on the right and so can be stored without loss of precision.
For example you can always do:
A narrowing assignment is a potential problem because the variable on the left isn't always capable of storing the result on the right.
Things might work ok if say the value stored in myInt is small enough to be stored in myByte - but equally it might not.
Widening assignments are performed by the system without you getting involved - and this is a general principle that goes beyond just numbers.
A narrowing assignment needs some help and it generally requires the programmer to explicitly specify how the types should be converted.
So suppose we do want to assign an int to a byte how do we do it?
The answer is to use a cast and this is again a more general mechanism than it appears. You can attempt to convert any type to any type with a cast but it doesn't always work or make sense!
To cast one type to another you simply use
This converts the value in myInt to a byte and stores it in myByte.
Simple and brutal.
If the int is actually in the range that a byte can represent then it works fine. If it isn't then all you get are the bottom eight bits of the 16 bit value. This often makes no sense numerically but some types of bit manipulation rely on it.
Unless you are doing bit manipulation casting a numerical value to a "smaller" type only makes sense if the value can be accurately represented by the smaller value.
So for example you can safely use casting to make byte arithmetic "safe" as in
Now even though the arithmetic promotes the byte to an int it is converted back again to a byte by the cast.
Notice that it doesn't take much to cause a cast to do something that you might not want. For example:
produces the answer -2. This makes sense if you know how the numbers are stored in binary signed format but unless you are doing some advanced bit manipulation this isn't particularly useful.
The same sorts of things occur if you cast a float or a double to int or an integer type. For example:
int myInt=(int) myDouble;
in this case the cast simply truncates the result - it throws way the fractional part to give you one.
What if you want to perform a more gentle and accurate sort of conversion?
The answer is to use the Math class and its numeric conversion methods all of which accept a double and return a double as the result:
- ceil returns the smallest integer not less than the specified double
- floor returns the largest integer not greater than the specified double.
- rint returns the integer that is closest to the specified double
There is also a round method which will accept an double or a float and return the closes integer as a long or an int respectively.
int myInt=(int) Math.floor(1.5);
stores 1 in myInt - notice you still need a cast as floor returns a double.
int myInt=(int) Math.ceil(1.5);
stores 2 in myInt.
There are lots of other useful mathematical methods included in the Math class and it is worth finding out more about.