Conversions

Figure 106. Widening from byte literal to short Slide presentation

Figure 107. Narrowing from int literal to char variable Slide presentation

Figure 108. A widening «ladder» Slide presentation
byte   b = 42;  // Narrowing: constant int literal to byte
short  s = b;   // Widening
int    i = s;   // Widening
long   l = i;   // Widening
float  f = l;   // Widening
double d = f;   // Widening

Figure 109. A narrowing «ladder» Slide presentation
double d = 14.23;
float  f  = (float) d;  // Narrowing
long   l  = (long)  f;  // Narrowing
int    i  = (int)   l;  // Narrowing
short  s  = (short) i;  // Narrowing
byte   b  = (byte)  s;  // Narrowing

exercise No. 27

int and char

Q:

Explain the following output:

Code Output
char a = 0;
a -= 1;
int i = a;
System.out.println(i);
65535

Why do we see a result of 65535 rather than -1?

Tip

Read about the a char's value range.

A:

In contrast to byte, short and int a two byte char represents no negative but only positive values and zero:

decimal binary
0 0000 0000 0000 0000
1 0000 0000 0000 0001
2 0000 0000 0000 0010
...
65535 ( 2 16 - 1 ) 1111 1111 1111 1111

Like with other integer types the above table behaves in a cyclic way with respect to additions at its top and and subtractions at its bottom:

Code Output
char a = 65535;
a += 1;
int i = a;
System.out.println(i);
0

On machine level this may be conceived as an (incomplete) subtract operation:

 0000 0000 0000 0000
-0000 0000 0000 0001
--------------------
 1111 1111 1111 1111


exercise No. 28

float vs. double

Q:

We consider:

Code Output
System.out.println( 3.14 );
System.out.println( 3.14f );
System.out.println( 3.14d );
3.14
3.14
3.14

There seems to be no difference between the three literals 3.14, 3.14f and 3.14d. Is this actually true?

Tip

Read the section about floating point literals in Java. Write code exhibiting possible differences.

Use e.g. System.out.format("%.16f\n", floatOrDoubleValue); for printing values with 16 digits precision.

A:

The System.out.println( 3.14f ) statement's output is actually truncated with respect to output precision. Forcing 16 fractional digits to become visible reads:

Code Output
System.out.format("%.16f\n", 3.14f);
3.1400001049041750

The value 3.1400001049041750 is the closest possible approximation to 3.14 when using a 4-byte IEEE float. A 3.14f double literal won't be exact either but doubles the number of representing bytes to 8 thereby enhancing its representational precision substantially. This causes unexpected results:

Code Output
System.out.println(3.14f - 3.14d);
1.0490417468034252E-7

This difference is a result of 3.14d providing four additional bytes of precision therefore matching the exact value of 314 100 better than 3.14f.

Regarding types we have:

Literal Comment
3.14f 4-byte float literal
3.14d 8-byte double literal
3.14 Equivalent to 3.14d

Assignments to variables of type double are thus always guaranteed to work:

Code Comment
double d = 3.14f;
o.K., assigning float to double (widening)
double d = 3.14d;
o.K., assigning double to double
double d = 3.14;
o.K., assigning double to double as well.

Assignments to variables of type float may fail:

Code Comment
float f = 3.14f;
o.K., assigning float to float
float f = 3.14d;
Error, assigning double to float
float f = 3.14;
Error, assigning (implicit) double to float as well.

exercise No. 29

int to char narrowing problems

Q:

Reconsidering Figure 107, “Narrowing from int literal to char variable ” we observe the following two related snippets yielding compile time errors

  1. int i = 65;
    char c = i;

    On contrary the following code compiles well:

    char c = 65;
  2. char c = 66200;

    On contrary the following code compiles well:

    char c = 64200;

Explain these errors and their underlying reasons and provide a solution if possible.

Tip

Which data types are involved? Think about narrowing conversions and type casting.

A:

  • Assigning an int to a char variable effectively narrows from four to two bytes and is thus prohibited. A fix requires an explicit type cast:

    int i = 65;
    char c = (char) i;

    Since 65 fits well into a char being limited by 2 16 - 1 our cast will not have any negative impact.

  • We consider the binary representations of 66200 and 64200:

    System.out.println(Integer.toBinaryString(66200)); // Yields 1_00000010_10011000
    System.out.println(Integer.toBinaryString(64200)); // Yields   11111010_11001000

    Thus 64200 fits into a two byte char whereas 66200 being larger than 2 16 - 1 does not.

exercise No. 30

Get a byte from 139

Q:

Consider:

int i = 139;
byte b = (byte) i;
System.out.println(b);

Explain in detail why execution results in a value of -117.

A:

A four byte int representation of 139 reads 00000000_00000000_00000000_10001011. The cast b = (byte) i will strip the leading three bytes leaving us with b containing 10001011.

Since byte values in Java are being represented as signed values in two-complement notation this equals decimal -117.

exercise No. 31

Ariane, I miss you!

Q:

Reconsidering the Ariane 5 maiden flight crash read the comment buried in the solution of Inventing tinyint. . Try to mimic a code portion in Java showing the catastrophic error.

Start with a double variable using a value being suitable to be assigned to a short variable using a cast (narrowing).

Then in a second step raise this value breaking your short variable's upper limit.

A:

We start from:

double level = 2331.12; // smaller than 32767 == Short.MAX_VALUE

short value = (short) level;

System.out.println(value);

Execution yields an expected integer output of 2331. However increasing our level variable's value from 2331.12 to 42331.12 yields an output of -23205 due to an overflow.