Mathematics in Java

Contact Us or call 1-877-932-8228
Mathematics in Java

Mathematics in Java

Looks and behaves like algebra, using variable names and math symbols:

int a, b, c, temp;
a = b/c + temp;
b = c * (a - b);

Basic Rules

  • What goes on the left of the = sign is called an lvalue. Only things that can accept a value can be an lvalue (usually this means a variable name - you can't have a calculation like a + b in front of the equal sign).
  • Math symbols are known as operators; they include:
    Operator Purpose (Operation Performed)
    + for addition
    - for subtraction
    * for multiplication
    / for division
    % for modulus (remainder after division)
    ( and ) for enclosing a calculation
  • Note that integer division results in an integer - any remainder is discarded.

Expressions

An expression is anything that can be evaluated to produce a value. Every expression yields a value.

Examples (note that the first few of these are not complete statements):

Two simple expressions:

a + 5
5/c

An expression that contains another expression inside, the (5/c) part:

b + (5/c)

A statement is an expression; this one that contains another expression inside - the b + (5/c) part, which itself contains an expression inside it (the 5/c part):

a = b + (5/c);

Since an assignment statement (using the = sign) is an expression, it also yields a value (the value stored is considered the result of the expression), which allows things like this:

d = a = b + (5/c);
  • The value stored in a is the value of the expression b + (5/c).
  • Since an assignment expression's value is the value that was assigned, the same value is then stored in d.
  • The order of processing is as follows:
    1. Retrieve the value of b.
    2. Retrieve the 5 stored somewhere in memory by the compiler.
    3. Retrieve the value of c.
    4. perform 5 / c
    5. Add the held value of b to the result of the above step.
    6. Store that value into the memory location for a.
    7. Store that same value into the memory location for d.

Here is a moderately complicated expression; let's say that a, b, and c are all double variables, and that a is 5.0, b is 10.0, and c is 20.0:

d = a + b * Math.sqrt(c + 5);
  1. Since the c + 5 is in parentheses, the compiler creates code to evaluate that first, but to perform the c + 5 operation, both elements must be the same type of data, so the thing the compiler creates is a conversion for the 5 to 5.0 as a double.
    d = a + b * Math.sqrt(c + 5.0);
  2. Then the compiler creates code to evaluate 20.0 + 5.0 (at runtime it would become 25.0), reducing the expression to:
    d = a + b * Math.sqrt(25.0);
  3. Next, the compiler adds code to call the Math.sqrt method to evaluate its result, which will be 5.0, so the expression reduces to:
    d = a + b * 5.0;
  4. Note that the evaluated result of a method is known as the return value, or value returned.
  5. Multiplication gets done before addition, the compiler creates that code next, to reduce the expression to:
    d = a + 50.0;
  6. Then the code will perform the addition, yielding:
    d = 55.0;
  7. And finally, the assignment is performed so that 55.0 is stored in d.

As implied by the examples we have seen so far, the order of evaluation of a complex expression is not necessarily from left to right. There is a concept called operator precedence that defines the order of operations.

Operator Precedence

Operator precedence specifies the order of evaluation of an expression.

Every language has a "table of operator precedence" that is fairly long and complex, but most languages follow the same general rules:

  • Anything in parentheses gets evaluated before what is outside the parentheses.
  • Multiply or divide get done before add and subtract.

Example

  • In the expression a = b + 5/c, the 5/c gets calculated first, then the result is added to b, then the overall result is stored in a.
  • The equal sign (=) is an operator; where on the table do you think it is located?

The basic rule programmers follow is: when in doubt about the order of precedence, use parentheses.

Try the following program:

Code Sample:

Java-Basics/Demos/ExpressionExample.java
public class ExpressionExample {
  public static void main(String[] args) {
    double a = 5.0, b = 10.0, c = 20.0;
    System.out.println("a+b is " + (a + b));
    System.out.println("a+b/c is " + (a + b  / c));
    System.out.println("a*b+c is " + (a * b + c));
    System.out.println("b/a+c/a is " + (b / a + c / a));
  }
}

Multiple Assignments

Every expression has a value. For an assignment expression, the value assigned is the expression's overall value. This enables chaining of assignments:

x = y = z + 1; is the same as y = z + 1; x = y;

i = (j = k + 1)/2; is the same as j = k + 1; i = j/2;

Quite often, you may need to calculate a value involved in a test, but also store the value for later use:

double x;
if ( (x = Math.random()) < 0.5 ) {
	System.out.println(x);
}

You might wonder why not just generate the random number when we declare x? In this case, that would make sense, but in a loop the approach shown above might be easier such that:

  • generates the random number and stores it in x.
  • as an expression, that results in the same value, which is then tested for less than 0.5, and the loop body executes if that is true.
  • the value of x is then available within the block.
  • after the loop body executes, another random number is generated as the process repeats.

It is usually not necessary to code this way, but you will see it often.

Order of Evaluation

The order of operand evaluation is always left to right, regardless of the precedence of the operators involved.

Code Sample:

Java-Basics/Demos/EvaluationOrder.java
public class EvaluationOrder {
  public static int getA() {
    System.out.println("getA is 2");
    return 2;
  }
  public static int getB() {
    System.out.println("getB is 3");
    return 3;
  }
  public static int getC() {
    System.out.println("getC is 4");
    return 4;
  }
  public static void main(String[] args) {
    int x = getA() + getB() * getC();
    System.out.println("x = " + x);
  }
}

The operands are first evaluated in left to right order, so that the functions are called in the order getA(), then getB(), and, lastly, getC()

But, the returned values are combined together by multiplying the results of getB() and getC(), and then adding the result from getA()

Bitwise Operators

Java has a number of operators for working with the individual bits within a value.

Operator
Description
Example
Effect
Bit Pattern
& Bitwise AND, combines individual bits with an AND operation, so that in the resulting value, a bit position is only 1 if that position had a 1 for both operands.
int a = 2; has the 2 bit set 0...00000010
int b = 6; has the 2 and 4 bits set 0...00000110
int c = a & b; results in 2 0...00000010
| Bitwise OR, combines individual bits with an OR operation, so that in the resulting value, a bit position is 1 if that position had a 1 for either operand.
int a = 2; has the 2 bit set 0...00000010
int b = 4; has the 4 bit set 0...00000100
int c = a | b; results in 6 0...00000110
^ Bitwise exclusive OR (XOR), combines individual bits so that any position that is the same in both operands yields a 0, any bits that differ yield a 1 in that position; this is often used in encryption, since repeating the operation on the result yields the original value again
int a = 3; has the 1 and 2 bits set 0...00000011
int b = 6; has the 2 and 4 bits set 0...00000110
int c = a ^ b; results in 5 0...00000101
int d = c ^ b; results in 3 again 0...00000011
~ Bitwise complement. Reverses the state of all bits.
int a = 0; has no bits set 0...00000000
int b = ~a; has all bits set 1...11111111

Bitwise Shift Operators

These operators shift the bits left or right within a 32-bit int value (they do not work with any other type).

Operator Description
Example Effect Bit Pattern
<< left shift the bits by the second operand
int a = 4; has the 4 bit set 0...00000010
int b = a << 2; now has the 16 bit set 0...00001000
>> right shift the bits by the second operand with sign-extension (if the first bit is a 1, new bits introduced to fill in on the left come in as 1 bits)
int a = -126; has all bits except the rightmost set to 1 10...0000010
int b = a >> 1; now has all bits set to 1 (the 0 rolled off the right end, and a 1 was added on the left to match the original leftmost bit; the resulting value is 63) 110...000001
>>> right shift the bits by the second operand without sign-extension (bits added on the left always come in as 0)
int a = -1; has all bits set to 1 11...1111111
int b = a >>> 31; now has all bits set to 0 except the rightmost (all bits except the first rolled off the right end, and 0's were added on the left 0000000...01

Compound Operators

Combine multiple effects in one operation: calculation and storage into memory

Operator
Purpose (Operation Performed)
++ increment a variable
-- decrement a variable; note that ++ and -- can precede or follow a variable
if preceding (called prefix), apply the operator and then use the resulting value
if following (called postfix), retrieve the value of the variable first, use it as the result of the expression, and then apply the operator
+= add an amount to a variable
-= subtract an amount from a variable
*= multiply a variable by an amount
/= divide a variable by an amount
%= set variable equal to remainder after division by an amount
&= perform bitwise AND between left and right, store result into left operand
|= perform bitwise OR between left and right, store result into left operand
^= perform bitwise XOR between left and right, store result into left operand
>>= shift the variable's bits to the right by an amount with sign-extension
>>>= shift the variable's bits to the right by an amount without sign-extension
<<= shift the variable's bits to the left by an amount

Compound Operator Examples

Statement
Result
i++; increment i
i--; decrement i
j = i++; retrieve current value of i, hold it as the result of the expression, assign its value to j, then increment i
j = ++i; increment i, then j = i;
x *= 3; x = x * 3;
y -= z + 5; y = y - (z + 5);

It is inevitable that a certification exam will ask a question that requires understanding the steps involved in a postfix increment or decrement: try the following program:

Code Sample:

Java-Basics/Demos/IncrementTest.java
public class IncrementTest {
  public static void main(String[] args) {
    int i = 0, j;
    
    i = i++;
    System.out.println("i = " + i);
    
    j = i++ + i;
    System.out.println("i = " + i + ", j = " + j);
  }
}
  • In the first statement, i = i++;, the original value of i (0) is retrieved and held. Then, i is incremented. But, after that, the held value of 0 is put back into i, overwriting the 1!
  • In the second part, j = i++ + i;, the operands are evaluated from left to right, but each operand is fully evaluated before proceeding to the next. Which means that the increment part of i++ has taken effect before the second appearance of i in the equation, so that the expression reduces to 0 + 1 (recall that the previous operation resulted in i being 0).

Expressions that Mix Data Types: Typecasting

Expressions will often mix different types of data, for example:

double x = 15.6 / 4;
double y = 12.2 + 15 / 4;

The compiler must choose a specific type of data (either integer or floating-point, and the specific size) for each individual expression it evaluates within a statement.

  • In general, the processor will choose the larger or more complex unit to work with.
  • In the first case the value 4 will be promoted to a double, which will then be used in the division.
  • The conversion is done one expression at a time within a statement; so, in the second example, the division will be performed with integer math, resulting in a value of 3, which will then be promoted to a double to finish the statement.

The process of changing the data type of a value is known a typecasting (or casting):

  • A wideningcast converts a smaller or less precise value into a larger or more precise type - this is done automatically (the compiler does an implicitcast, as above).
  • A narrowing cast converts a larger or more precise value into a smaller or less precise type (such as from double to int) - this must be coded with an explicit cast.
  • To code an explicit typecast, put the desired type in parentheses in front of the expression to be converted; for example:
    int a = (int) (15.6 / 4);
  • The division will be evaluated as before, meaning the 4 is promoted to a double, and the result is a double, but a double can't be stored in a, so the cast to int is necessary.
  • Note that casting is an operation, therefore it has a precedence (which is fairly high on the operator precedence table).

The allowable sequence of implicit casts is shown below: Integral promotion sequence

Small Integral Types and Expressions

One aspect of Java that is important to understand is the result of expressions involving the small integral types: byte, char, and short any expression involving these types, other than the compound assignment expressions, is done with int values, so that the result will always be an int.

Try the following (it is the same as the earlier postfix increment example, using byte instead of int):

byte i = 0, j = 6, k;
i++;
k = i + j;
System.out.println("i = " + i + ", j = " + j);

Note that the increment expression is accepted by the compiler; it is the simple addition in the third line that causes an error.

The Java Language Specification states the promotion rules as follows (note that this concept does not apply to all operators; again, the operators that include assignment do not use it):

When an operator applies binary numeric promotion to a pair of operands, each of which must denote a value of a numeric type, the following rules apply, in order, using widening conversions to convert operands as necessary:

  • If either operand is of type double, the other is converted to double.
  • Otherwise, if either operand is of type float, the other is converted to float.
  • Otherwise, if either operand is of type long, the other is converted to long.
  • Otherwise, both operands are converted to type int.
Next