Operators and expressions

Figure 149. The binary plus operator Slide presentation Create comment in forum
The binary plus operator

Figure 150. Binary operator output type Slide presentation Create comment in forum
Binary operator output type

exercise No. 35

int to short assignment Create comment in forum

Q:

Consider the following code segment:

Figure 151. int expression assignment
short a = 4; 
short sum = a + 7; 

Declaring a short variable a assigning 4.

Declaring a short variable sum assigning 4 + 7.This yields a compile time error:

Type mismatch: cannot convert from int to short

On contrary the following line will compile flawlessly:

Figure 152. Constant expression assignment
short sum = 4 + 7;

Explain this strange behaviour.

A:

Considering short sum = 4 + 7 the plus operator acts on two int operands. Thus the expression 4 + 7 is of type int. Both operands are static i.e. their values are known at compile time (rather than at run time). The 4 + 7 expression's value can thus be evaluated at compile time. The resulting value of 11 is within [ - 2 15 , - 2 15 - 1 ] so the compiler will safely cast and assign it to the variable sum of type short without any information loss.

The expression a + 7 contains a variable a of type short to the plus operator's left and an int literal 7 to its right. Thus the expression is of type int as well. However a compiler will consider the variable a's value to be unknown within the given expression at compile time (albeit humans will safely assume a value of 4 by virtue of the preceding statement). Therefore variable a's value could potentially exceed a short's range of values and thus cannot be assigned to the variable sum in a safe manner.

exercise No. 36

int to short assignment using final Create comment in forum

Q:

We reconsider a variant of Figure 151, “int expression assignment”:

final short a = 4;
short sum = a + 7;

This time the code compiles flawlessly. Explain the underlying reason being related to the final modifier's role.

A:

A final variable's value cannot change. Thus the expression a + 7 is fully equivalent to 4 + 7 and can thus be evaluated at compile time. Like in the preceding Figure 152, “Constant expression assignment” code sample the resulting value of 11 neatly fits into the variable sum of type short.

exercise No. 37

Dividing values Create comment in forum

Q:

Consider the following statement:

System.out.println(8 / 9);

The output is 0 rather than 0.888888... . Explain this result.

A:

The divide operator acts on two int literal values 8 an 9. Thus irrespective of the possibly intended floating point result the resulting type is int .

According to https://docs.oracle.com/javase/specs/jls/se7/html/jls-5.html#jls-5.1.3-300-A-2 the floating point value 0.88888... will be rounded toward zero yielding an int value of 0 rather than 1.

exercise No. 38

Strange things happen Create comment in forum

Q:

  1. Consider the following code snippet:

    byte a = 127;
    System.out.println("Current value=" + a + ", now adding 1 to it");
    a++;
    System.out.println("New value=" + a);

    This will produce the following output:

    Current value=127, now adding 1 to it
    New value=-128

    Explain this strange behaviour on bit level.

  2. Moreover the following yields a compile time error:

    byte a = 127;
    System.out.println("value=" + a);
    a = a + 1; // Error: Type mismatch: cannot convert from int to byte
    System.out.println("New value=" + a);

    What do you learn about the two operators + an a++? Explain this error's cause.

Tip

You may want to read the overview section on statements in [Kurniawan].

A:

  1. A byte variable ranges from -128 to +127. Thus incrementing 127 by 1 yields -128 and thus an overflow error.

    Since Java uses Two's complement representation we have:

    01111111 127
    +00000001 +1
    =10000000 =-128

    On machine level the above calculation is just an ordinary addition.

    Conclusion: Watch out when doing (integer) arithmetic!

  2. The compile time error is due to the definition of the + operator in Java always returning an int rather than a byte. Consider:

    byte a = 120, b = 10;
    System.out.println(a + b);

    This yields the expected output of 130 and corresponds to an int value.

    If the expression a + b was of data type byte in Java an arithmetic overflow as in the subsequent code example would occur:

    byte a = 120, b = 10;
    
    byte sum = (byte) (a + b);
    
    System.out.println(sum);

    The explicit type conversion (a so called type cast or cast for short) forces the 4-byte int into a one-byte variable sum thereby loosing its original value and returning -126 instead.

    Conclusion: a = a + 1 and a++ (surprisingly) differ in behaviour when being applied to non-int variables.

exercise No. 39

Adding values Create comment in forum

Q:

Consider the following code:

System.out.println(2147483647 + 1);
System.out.println(2147483647 + 1L);

This yields:

-2147483648
2147483648

Explain this result. Please refrain from answering Thats what bankers do!

A:

The value 2147483647 is actually the largest possible int value Integer.MAX_VALUE. The plus operator in the first expression 2147483647 + 1 acts on two operands of type int. Thus the resulting sum will be of type int as well irrespective of its value.

On binary level adding an int value of 1 results in:

  01111111_11111111_11111111_11111111    2147483647
+ 00000000_00000000_00000000_00000001   +         1
-------------------------------------  ------------
  10000000_00000000_00000000_00000000   -2147483648

With respect to two-complement representation of signed int values this is actually an overflow error: There simply is no positive int value of 2147483648 in Java. See http://docs.oracle.com/javase/specs/jls/se7/html/jls-5.html#jls-5.1.3-220 for details.

On contrary the plus operator in the expression 2147483647 + 1L acts on an int to its left and a long to its right. The result will thus be of type long:

                                      01111111_11111111_11111111_11111111    2147483647
+ 00000000_00000000_00000000_00000000_00000000_00000000_00000000_00000001   +         1
-------------------------------------------------------------------------  ------------
  00000000_00000000_00000000_00000000_10000000_00000000_00000000_00000000    2147483648

Due to a long's larger allocation of eight rather than four bytes execution reveals no overflow problem thus yielding the expected result.

exercise No. 40

Representational float and double miracles Create comment in forum

Q:

Consider and execute the following code snippet:

public static void main(String[] args) {
  final double a = 0.7;
  final double b = 0.9;
  final double x = a + 0.1; // 0.8
  final double y = b - 0.1; // 0.8
  System.out.println(x == y);
}

Which outcome do you expect? Explain the execution's result and propose a solution.

Tip

You will have to replace the == operator by something more appropriate addressing limited arithmetic precision.

A:

The expression x == y evaluates to false. This surprising result is due to limited precision regarding both float and double IEEE representations: A given value will be approximated as close as possible.

Adding System.out.println(x - y) yields a value of -1.1102230246251565E-16 denoting the representational deviation of x and y.

Comparing float and double values thus requires providing a representational distance limit below which two values will be regarded as equal:

final double a = 0.7;
final double b = 0.9;
final double x = a + 0.1;
final double y = b - 0.1;
System.out.println(Math.abs(x - y) < 1.E-14);

The last line represents the boolean expression | x - y | < 10 - 14 . So two values will be regarded as equal if their mutual distance is less than 0.00000000000001.

Figure 153. Detecting arithmetic overflow (Java 8+) Slide presentation Create comment in forum
try {
    int sum = Math.addExact(2147480000, 2147480000);
    System.out.println("sum = " + sum);
} catch (ArithmeticException ex) {
    System.err.println("Problem: " + ex.getMessage());
}
Problem: integer overflow

Figure 154. Dividing by zero Slide presentation Create comment in forum
double f = 34.3 / 0;
System.out.println("Value: " + f);
Value: Infinity

exercise No. 41

Expressions involving infinity Create comment in forum

Q:

Figure 154, “Dividing by zero ” raises some interesting questions:

  1. What happens if we add e.g. 1000 to a variable containing a value of Infinity?

  2. What happens if we add or subtract two variables both containing a value of Infinity?

A:

  • double f = 1. / 0;
    double difference = f - 1000;
    System.out.println("Difference: " + difference);
    Difference: Infinity
  • double f = 1. / 0;
    double g = 1. / 0;
    double difference = f - g;
    System.out.println("Difference: " + difference);
    Difference: NaN

    Explanation: This represents a special not a number encoded value.

Figure 155. Operator type behaviour Slide presentation Create comment in forum
Operator type behaviour

Figure 156. Binary operator type examples Slide presentation Create comment in forum
Left Right Out Examples
boolean boolean boolean |, &, &&, ||, ^
int int int

+, -, *, /, % (read here!)

int long long
byte short int
double float double
int float float
char byte int

The careful reader may stumble upon the absence of e.g. a «+» operator turning two byte values a and b into an expression a + b of type byte rather than int. This is due to a Java Virtual Machine design decision leading to a limited set of computational types:

Given the Java Virtual Machine's one-byte opcode size, encoding types into opcodes places pressure on the design of its instruction set. If each typed instruction supported all of the Java Virtual Machine's run-time data types, there would be more instructions than could be represented in a byte. Instead, the instruction set of the Java Virtual Machine provides a reduced level of type support for certain operations. In other words, the instruction set is intentionally not orthogonal. Separate instructions can be used to convert between unsupported and supported data types as necessary.

exercise No. 42

Calculating a circle's area Create comment in forum

Q:

The area a of a given circle having radius r is being obtained by a = π × r 2 . Complete the following code to calculate the result and write it to standard output using System.out.println(...):

public static void main(String[] args) {

   double radius = 2.31;   // A circle having a radius (given e.g. in mm).
   double pi = 3.1415926;  // Constant relating a circle's radius,
                           //perimeter and area.
 
  System.out.println( /* TODO: Write the circle's area to standard output */);
}

Tip

You may want to read the overview section on statements in [Kurniawan].

A:

Using a mere expression
public static void main(String[] args) {

   double radius = 2.31;   // A circle having a radius (given e.g. in mm).
   double pi = 3.1415926;  // Constant relating a circle's radius,
                           //perimeter and area.

   System.out.println(pi * radius * radius);
}
Using a variable

Instead of immediately using the expression as an argument to System.out.println(...) we may assign its value to a variable prior to output creation:

public static void main(String[] args) {

   double radius = 2.31;   // A circle having a radius (given e.g. in mm).
   double pi = 3.1415926;  // Constant relating a circle's radius,
                           //perimeter and area.

   double area = pi * radius * radius;
   System.out.println(area);
}

exercise No. 43

Calculating a circle's area avoiding accidental redefinition Create comment in forum

Q:

In Exercise Calculating a circle's area you calculated a given circle's area:

public static void main(String[] args) {

  double radius = 2.31;   // A circle having a radius (given e.g. in mm).
  double pi = 3.1415926;  // Constant relating a circle's radius, perimeter
                              //and area.

  double area = pi * radius * radius;
  System.out.println(area);
}

Though there is nothing wrong with this approach it is error prone: A careless programmer might accidentally redefine the value of pi:

double pi = 3.141592653589793;

double radius = 2.3; // Computing a circle's area
System.out.println("A circle of radius " + radius + " will cover an area of " +
  pi * radius * radius);

pi = -4; // Woops, accidential redefinition

radius = 1.8;

System.out.println("A circle of radius " + radius + " will cover an area of " +
   pi * radius * radius);

Modify the above code to avoid this type of error.

Tip

A:

The solution is straightforward. We just add a final modifier to the definition of our variable pi:

final  double pi = 3.141592653589793;
...
pi = -4; 
...

A final modifier prohibits subsequent variable assignments thus keeping its initially assigned value constant.

The assignment attempt is being flagged as a compile time error:

Cannot assign a value to final variable 'pi'

As a rule of thumb: Whenever you intend a variable not to change after an initial assignment use final declaring it to remain constant.

In addition refactoring our variable pi using capital letters reflecting the naming convention for constants. This is does not change program execution in any way but enhances code readability:

final double PI = 3.141592653589793;
double radius = 2.3; // Computing a circle's area
System.out.println("A circle of radius " + radius + " will cover an area of " +
  PI * radius * radius);

PI = -4; // Compile time error

radius = 1.8;

System.out.println("A circle of radius " + radius + " will cover an area of " +
   PI * radius * radius);

exercise No. 44

Turning weeks into seconds Create comment in forum

Q:

Consider:

final short
  weeks = 2,
  days = 3,
  hours = 14,
  minutes = 32,
  seconds = 55;

final int secondsElapsed = ...; // TODO: assign elapsed seconds corresponding to previous time frame.

System.out.println(secondsElapsed);

Create an expression based on the variables weeks, days, hours, minutes and seconds to calculate the number of seconds elapsed for the given time period of two weeks, three days and so on.

After you have completed this task read about Horner's rule and try to improve your solution with respect to execution time.

A:

A straightforward solution reads:

final short
  weeks = 2,
  days = 3,
  hours = 14,
  minutes = 32,
  seconds = 55;

final int secondsElapsed =
  seconds + 60 * minutes + 60 * 60 * hours + 60 * 60 *  24 * days + 60 * 60 *  24 * 7 * weeks;

System.out.println(secondsElapsed);

This requires four additions and 10 multiplications. Horner's rule allows for:

...
final int secondsElapsed =
  seconds + 60 * (minutes + 60 * (hours + 24 * (days + 7 * weeks)));
...

This still leaves us with four additions but just 4 instead of 10 multiplications.

Within the given context the difference in execution time can be neglected. But in a larger application the calculation in question might have to be repeated millions of times giving rise to a substantial gain with respect to execution time.

exercise No. 45

Turning seconds into weeks Create comment in forum

Q:

This exercise is about reversing Turning weeks into seconds namely decomposing a given value of elapsed seconds into weeks, days, hours, minutes and seconds:

final int secondsElapsed = 1521175;

final int weeks = ...; // TODO
final int days = ...;// TODO
final int hours = ...;// TODO
final int minutes = ...;// TODO
final int seconds = ...;// TODO

System.out.println(weeks + ", " + days + ", " + hours + ", " + minutes + ", " + seconds);

Tip

As an example consider decomposing 192 seconds into minutes and seconds:

  • Integer division 192 / 60 seconds yields 3 minutes.

  • We get the remaining seconds by virtue of the remainder operator 192 % 60.

Thus 192 seconds equal 3 minutes and 12 seconds

A:

We extend the given minute calculation example to all 5 desired values. For the sake of convenience the number of seconds per minute, per hour and so on are being calculated beforehand:

final int secondsElapsed = 1521175;

// Defining helpful constants
//
final int
  secondsPerMinute = 60,                    // 60 minutes per hour
  secondsPerHour =   60 * secondsPerMinute, // 3600 seconds per hour
  secondsPerDay =    24 * secondsPerHour,   // 86400 seconds per day
  secondsPerWeek =    7 * secondsPerDay;    // 604800 seconds per week

int remainingSeconds = secondsElapsed;

final int weeks = remainingSeconds / secondsPerWeek;
remainingSeconds = remainingSeconds % secondsPerWeek;

final int days = remainingSeconds / secondsPerDay;
remainingSeconds %= secondsPerDay;

final int hours = remainingSeconds / secondsPerHour;
remainingSeconds %= secondsPerHour;

final int minutes = remainingSeconds / secondsPerMinute;
remainingSeconds %= secondsPerMinute;

final int seconds = remainingSeconds;

System.out.println(weeks + ", " + days + ", " + hours + ", " + minutes + ", " + seconds);

exercise No. 46

Using predefined Java standard library constants Create comment in forum

Q:

In the previous exercise we coded:

final double PI = 3.141592653589793;
double radius = 2.3; // Computing a circle's area
System.out.println("A circle of radius " + radius + " will cover an area of " +
  PI * radius * radius);

Do we actually have to provide the value of pi (3.141592653589793) ourself?

Tip

Consider the standard Math library.

A:

The solution is straightforward using Math.PI:

double radius = 2.3; // Computing a circle's area
System.out.println("A circle of radius " + radius + " will cover an area of " +
  Math.PI * radius * radius);

exercise No. 47

Converting temperature values Create comment in forum

Q:

Write an application converting temperature values being represented as degree centigrade to kelvin and Fahrenheit:

public static void main(String[] args) {

  double temperatureCelsius = 23.2;

      ...

  System.out.println("Celsius: " + temperatureCelsius);
  System.out.println("Kelvin: " + temperatureKelvin);
  System.out.println("Fahrenheit: " + temperatureFahrenheit);
}

A:

public static void main(String[] args) {

  double temperatureCelsius = 23.2;

  double
      temperatureKelvin = temperatureCelsius + 273.15,
      temperatureFahrenheit = 9 * temperatureCelsius / 5 + 32;

  System.out.println("Celsius: " + temperatureCelsius);
  System.out.println("Kelvin: " + temperatureKelvin);
  System.out.println("Fahrenheit: " + temperatureFahrenheit);
}

exercise No. 48

Time unit conversion Create comment in forum

Q:

This is a two part exercise:

  1. Write an application converting a (seconds, minutes ,hours) time specification to seconds:

    public static void main(String[] args) {
    
      final int
          seconds = 31,
          minutes = 16,
          hours = 4;
    
      int timeInSeconds ...
    
      System.out.println("Time in seconds:" + timeInSeconds);
    }

    The expected output reads:

    Time in seconds:15391
  2. Reverse the previous part of this exercise: Convert a time specification in seconds to (seconds, minutes ,hours) as in:

    public static void main(String[] args) {
    
      final int timeInSeconds = 15391;
    
        ...
    
      System.out.println("Hours:" +  hours);
      System.out.println("Minutes:" +  minutes);
      System.out.println("Seconds:" +  seconds);
    }

    The expected output reads:

    Hours:4
    Minutes:16
    Seconds:31

    Tip

    Consider the remainder operator % (modulo operator).

A:

  1. A straightforward solution reads:

    public static void main(String[] args) {
    
      final int
        seconds = 31,
        minutes = 16,
        hours = 4;
    
      final int timeInSeconds = seconds + 60 * (minutes + 60 * hours);
    
      System.out.println("Time in seconds:" + timeInSeconds);
    }
  2. public static void main(String[] args) {
    
      final int timeInSeconds = 15391;
    
      final int minutesRemaining = timeInSeconds / 60;
      final int seconds = timeInSeconds % 60;
    
      final int hours = minutesRemaining / 60;
      final int minutes = minutesRemaining % 60;
    
      System.out.println("Hours:" +  hours);
      System.out.println("Minutes:" +  minutes);
      System.out.println("Seconds:" +  seconds);
    }

exercise No. 49

Interest calculation Create comment in forum

Q:

We want to calculate the compounded interest starting from an initial capital, a given annual interest rate and a duration of three years. Consider the following code fragment:

public static void main(String[] args) {

  final double initialCapital = 223.12;
  final double interestRate = 1.5;

  System.out.println("Initial capital:" + initialCapital);
  System.out.println("Annual interest rate:" + interestRate);

  // TODO ...

  System.out.println("Capital after three years:" + ...);
}

The expected output is:

Initial capital:223.12
Annual interest rate:1.5
Capital after three years:233.31175902999993

Tip

In case you are unsure read about calculating the compounded interest.

A:

We obtain the compounded interest by multiplying the initial capital by 1 + r / 100 for each year where r represents the given interest rate.

Since we have not yet introduced loops this multiplication has to be repeated three times:

public static void main(String[] args) {

  final double initialCapital = 223.12;
  final double interestRate = 1.5;

  System.out.println("Initial capital:" + initialCapital);
  System.out.println("Annual interest rate:" + interestRate);

  final double factor = 1. + interestRate/100.;
  double capitalAtThreeYears = initialCapital;

  capitalAtThreeYears *= factor; // Year 1
  capitalAtThreeYears *= factor; // Year 2
  capitalAtThreeYears *= factor; // Year 3

  System.out.println("Capital after three years:" + capitalAtThreeYears);
}

We might as well use a single arithmetic expression to achieve the same result:

public static void main(String[] args) {

  final double initialCapital = 223.12;
  final double interestRate = 1.5;

  System.out.println("Initial capital:" + initialCapital);
  System.out.println("Annual interest rate:" + interestRate);

  final double factor = 1. + interestRate/100.;
  final double capitalAtThreeYears =
        initialCapital * factor * factor * factor;

  System.out.println("Capital after three years:" + capitalAtThreeYears);
}

In the section called “Interest calculations” we will present a more elaborate solution based on loops and class methods.

exercise No. 50

Summing short and char Create comment in forum

Q:

Consider the following snippet:

short s = 1;
char c = 'A'; // ASCII 65
System.out.println(s + c);

Execution results in 66. What is the s+c expression's type?

Tip

Try to assign the expression to another variable and experiment using type candidates. Try to make an educated guess explaining the result.

A:

Both short and char require two bytes in Java. It is thus surprising that a mixed expression has got neither of both input types:

short s = 1;
char c = 'A';
short resultShort = s + c; // Incompatible types Required: short found: int
char resultChar= s + c;    // Incompatible types Required: char found: int

According to the compiler's error message the expression s + c is of type int. Why choosing a result type being twice the size of both input types?

The two input types have different ranges:

short

Signed integer value ranging from - 2 15 to 2 15 - 1 .

char

Unsigned integer value ranging from 0 to 2 16 - 1 .

A promotion to int guarantees correct results in all circumstances.

Figure 157. Operator examples Slide presentation Create comment in forum
//Integer
i++;             i = i + 1;  // Increment by one
i--;             i = i - 1;  // Decrement by one
i += b;          i = i + b;  // Raise by b's value
i %= 3;          i = i % 3;  // Modulus of 3

// boolean
                    b = !b;  // Switching true <--> false

exercise No. 51

Guessing results Create comment in forum

Q:

Consider the following code segment:

int a = 3;
a++;          // Incrementing a by 1 --> a==4

int b = a;    // TODO

b--;          // TODO
--b;          // TODO

int c = b;    // TODO

b = ++a;      // TODO
int e = a++;  // TODO

a *= b;       // TODO

System.out.println("a=" + a);
System.out.println("b=" + b);
System.out.println("c=" + c);
System.out.println("e=" + e);

We want to guess the expected result. Copy/paste the above code into a main() method body within your IDE of choice.

Do not execute this code yet but replace the TODO strings by guessing the respective variable's value beforehand as in line 2:

a=...

b=...

c=...

e=...

After finishing your guesses execute your code and (possibly) start wailing about your success rate.

Tip

Both x++ (postfix notation) and ++x (infix notation) are expressions themselves which might even be rewritten as (x++) and (++x) for the sake of clarity. The difference is not about operator precedence rules but simply about the values of these expressions when being assigned to other variables.

A:

As inferred by the hint the biggest problem is about understanding postfix and infix notation of the operators ++ and --. A corresponding expression evaluates to:

  • a = x++ yields a ==x: The value of x before incrementing it.

  • a = ++x yields a ==(x + 1): The value of x after incrementing it.

The rest is just obeying the due diligence rule set:

int a = 3;
a++;          //Incrementing a by 1 --> a==4

int b = a;    // Assigning value of a --> b==4

b--;          // Decrementing b by 1 --> b==3
--b;          // Decrementing b by 1 --> b==2

int c = b;    // c == 2;

b = ++a;      // Incrementing a by 1 -->a==5, then assigning to b --> b == 5
int e = a++;  // Assigning a to e --> e==5, then incrementing a --> a==6

a *= b;       // Multiplying a with b and assigning the result to a --> a==30

System.out.println("a=" + a);
System.out.println("b=" + b);
System.out.println("c=" + c);
System.out.println("e=" + e);

exercise No. 52

Cleaning up the mess Create comment in forum

Q:

Some developers follow the rule It was hard to write, it should be hard to understand as well. One such proponent codes:

int a = 3, b = 6, c = 2;

a += (a = 2) + ++a - ++b % c--;

System.out.println("a = " + a + ", b = " + b + ", c = " + c);

Execution results in:

a = 7, b = 7, c = 1

Decompose this cryptic assignment into a series of multiple elementary ones like e.g. a++ by possibly introducing one or more helper variables. Thus your code shall become longer but better to understand.

Tip

Read about evaluation of expressions and operator precedence.

A:

We start by modifying the line in question:

a = a + (a = 2) + ++a - ++b % c--;

The expression on the right hand side will be decomposed by the Java compiler into a sum of four subexpressions to be evaluated from left to right:

  1. a

  2. a=2

  3. ++a

  4. ++b % c--

    This one deserves further attention: The % operator will act on b's value after incrementing (infix notation) and c's value before decrementing (postfix notation).

We introduce a helper variable sum for decomposing our code into the above described four subexpressions:

int a = 3, b = 6, c = 2;

int sum = a;  // First subexpression
a = 2;
sum += a;     // Second subexpression
a++;
sum += a;     // Third subexpression
b++;
sum -= b % c; // Fourth subexpression
c--;

a = sum;      // Assigning the result

System.out.println("a = " + a + ", b = " + b + ", c = " + c);