slanted W3C logo

Day 03 — Arithmetic

Arithmetic in Java looks pretty much like the arithmetic you learned in math, but there are some surprises you need to know about.

Arithmetic Operators for int Types

Assume that you have the following declarations for each example in the table below:

int x = 14;
int y = -7;
Operator Name Example Value
+ unary plus operator +x
+y
14
-7
- unary minus operator -x
-y
-14
7
* mulitplication operator x * y -98
/ division operator x / y -2
% remainder operator x % y 0
+ addition operator x + y 7
- subtraction operator x - y 21

Surprise!

How do you represent the passage of time on a computer? A widely used method is to store the number of seconds that have elapsed since a certain date.

Assuming that there are exactly 24 hours in a day and 365 days in a year, write a Java program that uses int literals (or variables) to calculate the:

  1. number of seconds in a year
  2. number of seconds in 70 years
  3. number of minutes represented by 30 seconds

Your program should use int variables, and it should print the results to the console.

Year 2038

Mathmatical Value Java Value
seconds per year 31 536 000 31536000
seconds in 70 years 2 207 520 000 -2087447296
mins in 30 secs 0.5 0

Many existing operating systems represent the passage of time using an integer type that is similar to Java's int. Such systems measure time elapsed since midnight January 1, 1970. The Year 2038 Problem refers to the fact that this time keeping system fails on January 19, 2038 (a bit more than 68 years after the starting date of January 1, 1970).

What is an int?

The Java type int is used to represent positive and negative whole numbers within a specified range.

Minimum Value Maximum Value
-231 = -2147483648 231 - 1 = 2147483647

Closure

All of the built-in arithmetic operations satisfy the closure property: the result of an arithmetic operation has the same type as the type of the operands (e.g. the sum of two int variables is an int value). This produces some results that are surprising to novice programmers.

Expression Mathmatical Value Java Value
2000000000 + 150000000 2150000000 -2144967296
-2000000000 - 150000000 -2150000000 2144967296
7 / 2 3.5 3
3 / 0 ArithmeticException

int Division

The Java division operator is the / symbol.

Satisfying closure means that dividing two int variables must produce an int result. Java accomplishes this by discarding the fractional part of the result:

Expression True Division Java Division
6 / 2 3 3
7 / 2 3.5 3
1 / 2 0.5 0
-9 / 5 -1.8 -1
9 / -5 -1.8 -1
3 / 0 ArithmeticException

int Remainder

Java also provides an operator to compute the remainder after division. The remainder operator is the % symbol.

Java Remainder Expression Java Remainder
6 % 2 0
7 % 2 1
1 % 2 1
-9 % 5 -4
9 % -5 4
3 % 0 ArithmeticException

Your Turn

Write a Java program that computes the number of quarters, dimes, nickels, and pennies you would need to make 94 cents. You should compute the number of quarters first, followed by the number of dimes, followed by the number of nickels, followed by the number of pennies.

Overflow

Closure requires that the result of an arithmetic operation with two int literals or variables also be of type int. What happens when we add 1 to the maximum value that can be represented by the int type? What happens when we subtract 1 from the minimum value that can be represented by the int type? When a value falls outside of the range that the int type can represent the result is arithmetic overflow.

Java ensures closure by treating the range as circular (adding 1 to the maximum int value produces the minimum int value, and subtracting 1 from the minimum int value produces the maximum int value).

public class IntOverflowExample
{
   public static void main(String[] args)
   {
      int max =  2147483647;
      System.out.println(max + 1);
      int min = -2147483648;
      System.out.println(min - 1);
   }
}

Unary int Operators

The operators we have seen so far are called binary operators because they require two operands. Java defines six unary operators that require one operand.

Unary Plus Operator

The unary plus operator + simply indicates a positive value. Note that you cannot use the operator to convert a negative value to a positive value; thus, this operator does not do anything when you use it on an int literal or variable.

The following program prints the number 17 on three lines:

public class IntUnaryPlusExample
{
   public static void main(String[] args)
   {
      int x = 17;
      System.out.println(x);

      // unary plus applied to an int literal
      int y = +17;
      System.out.println(y);

      // unary plus applied to an int variable
      y = +x;
      System.out.println(y);
   }
}

Unary Minus Operator

The unary minus operator - negates an expression.

The following program prints the number -17 on two lines:

public class IntUnaryMinusExample
{
   public static void main(String[] args)
   {
      int x = 17;

      // unary minus applied to an int variable
      y = -x;
      System.out.println(y);

      // unary minus applied to an expression
      y = -(14 + 3);
      System.out.println(y);
   }
}

Unary Increment and Decrement Operators

A common occurrence in computer programming is increasing (incrementing) or decreasing (decrementing) the value of a variable by 1. Java provides the increment operator ++ and the decrement operator -- that can be used immediately before or after a variable of type int.

public class IntIncrementDecrementExample1
{
   public static void main(String[] args)
   {
      int x = 0;
      
      ++x;
      // the value of the variable named x is now 1

      --x;
      // the value of the variable named x is now 0

      x++;
      // the value of the variable named x is now 1
      
      x--;
      // the value of the variable named x is now 0
   }
}

Notice that the placement of the operator (before and after the variable) was unimportant in this example. The placement becomes important when you apply the operator to a variable that is used in a larger expression.

Prefix Unary Increment and Decrement Operators

The prefix version of the operator occurs when the operator is placed in front of the variable. Java uses the incremented or decremented value of the variable in the expression for prefix increment or decrement.

Expression Value of y Final Value of x
int x = 0;
int y = 10 + ++x;
10 + (1) ⇒ 11 1
int x = 5;
int y = --x + 3;
(4) + 3 ⇒ 7 4
public class IntPrefixIncrementExample
{
   public static void main(String[] args)
   {
      int x = 10;
      System.out.println(++x);
      // should print 11
   }
}

The value of the expression ++x is the value of x incremented by 1.

Postfix Unary Increment and Decrement Operators

The postfix version of the operator occurs when the operator is placed after the variable. Java uses the current value of the variable in the expression for postfix increment or decrement.

Expression Value of y Final Value of x
int x = 0;
int y = 10 + x++;
10 + (0) ⇒ 10 1
int x = 5;
int y = x-- + 3;
(5) + 3 ⇒ 8 4
public class IntPostfixDecrementExample
{
   public static void main(String[] args)
   {
      int x = 10;
      System.out.println(x--);
      // should print 10
   }
}

The value of the expression x-- is the current value of x.

Operator Precedence

When you use multiple operators in the same expression you need to consider the order that the operators are evaluated. Each operator has a precedence level; operators with a higher precedence level are evaluated before ones with a lower level.

Precedence Operator
highest ++, -- postfix operators
++, --, +, - prefix unary operators
*, /, % multiply, divide, remainder
+, - addition, subtraction
lowest = assignment

Like regular arithmetic, multiplication and division (and remainder) have higher precedence than addition and subtraction.

Like regular arithmetic, expressions inside of parentheses are always evaluated first.

Precedence Examples

Assume that for each of the following examples shown in the table below we have the declarations:

int x = 10;
int y = 15;
Expression Evaluation
5 * x + y (5 * x) + y
(5 * 10) + y
50 + y
50 + 15
65
++x * y (++x) * y
11 * y
11 * 15
165
y-- * (x - 8) y-- * (10 - 8)
y-- * 2
15 * 2
30

Association

Expressions with multiple binary operators (addition, subtraction, multiplication, division, remainder) of the same precedence are evaluated from left to right. These operators are said to be left-associative.

Assume that for each of the following examples shown in the table below we have the declarations:

int x = 10;
int y = 15;
Expression Evaluation
5 + x + y (5 + x) + y
(5 * 10) + y
15 + y
15 + 15
30
x * 6 / 2 % y (x * 6) / 2 % y
60 / 2 % y
(60 / 2) % y
30 % y
30 % 15
0
50000 * 50000 / 50000 (50000 * 50000) / 50000
-1794967296 / 50000
-35899
50000 / 50000 * 50000 (50000 / 50000) * 50000
1 * 50000
50000

An Arithmetic Quiz Program

You can test your understanding of operator precedence and association by running the ArithmeticOperatorGame.

  1. Download the two Java source code files to your Working folder:
    ArithmeticOperatorView.java
    ArithmeticOperatorGame.java
  2. Compile the source code files. You can compile both at the same time with the command:
    javac ArithmeticOperator*java
  3. Run the program with the command:
    java ArithmeticOperatorGame

Type long

The Java type long is used to represent positive and negative whole numbers within a specified range that is wider than the range for int.

Minimum Value Maximum Value
-263 = -9,223,372,036,854,775,808 263 - 1 = 9,223,372,036,854,775,807

Type long supports all of the operators supported by type int. A long literal is a whole number followed by an L that is inside the range given above; for example:

public class LongLiteralExamples
{
   public static void main(String[] args)
   {
      long zero = 0L;
      long negFive = -5L;
      long seventyYrsInSecs = 60L * 60L * 24L * 365L * 70L;
   }
}

8 bytes are used to store a variable of type long.

Mixing int and long 1

You are allowed to use a value of type int whenever a value of type long is required. The Java compiler will automatically apply a widening conversion to the int value to convert it to a long value (we say that the int value is promoted to a long value).

public class IntToLong
{
   public static void main(String[] args)
   {
      int x = 5;

      long y = x; 
      // y is assigned the int value of x

      long z = 10 * 10;
      // z is assigned the int value of 100
   }
}

In the above example, the statement long y = x; leaves the variable named x unchanged (i.e. x does not change its type to long). Instead, the compiler looks up the value of x and converts the value to type long.

Mixing int and long 2

The Java compiler will not let you use a value of type long where a value of type int is required (even if the long value is inside the range that can be stored by int). Converting a long value to an int value is an example of a narrowing conversion.

When the situation arises where you want to use a long value where an int is required, you must explicitly cast the long value:

public class LongToInt
{
   public static void main(String[] args)
   {
      long seventyYrsInSecs = 60L * 60L * 24L * 365L * 70L;
      int secsPerYr = (int) (seventyYrsInSecs / 70L);
   }
}

Casting a long value to an int value will produce unusual results if the original long value does not fall in the range allowed by int.

Mixing int and long with Operators

If you use an arithmetic operator with an int and a long operand, the Java compiler will automatically promote the int value to type long. The resulting value of the operation will be have type long.

public class MixedIntLongExample
{
   public static void main(String[] args)
   {
      long x = 5 + 100L;

      // next statement will cause a compilation error
      int y = 5 + 100L;
   }
}

In the above example, the expression 5 + 100L will be evaluated by the compiler as:

⇒ (long)(5) + 100L
⇒ 5L + 100L
⇒ 105L

The resulting long value cannot be assigned to the int variable y without a cast.

Self Check

  1. Can you compile and run all of the example programs shown in today's slides? Do you understand what they are trying to show?
  2. Do you understand the concepts listed in the Summary of Key Concepts on page 35 of textbook (concepts 12—17)?
  3. Can you answer the Review Questions on page 36 of the textbook (questions 19 and 20)?
  4. Can you do Exercises 1.18 and 1.19 in the textbook?

To Do For Next Lecture

  1. Finish reading Chapter 1 in the textbook.
  2. Explain the output of the program shown below:
    • taken from the book Java Puzzlers by Joshua Bloch and Neal Gafter
public class LongDivision
{
   public static void main(String[] args)
   {
      // milliseconds in a day
      long millisPerDay = 1000 * 60 * 60 * 24;

      // microseconds in a day
      long microsPerDay = 1000 * 1000 * 60 * 60 * 24;

      // prints 1000?
      System.out.println(microsPerDay / millisPerDay);
   }
}