## 1. Mathematics

Integers and floating point numbers already appeared in the first exercises; we were using the common mathematical operators to crunch numbers. But Java does not have an operator for everything, and so the class `Math` offers further methods and constants; early on we used `Math.random()`, for example. In the following tasks of this chapter, we will focus on various roundings in particular, and we will look at methods of the `Math` class. In addition, the `java.math` package provides two classes that can be used to represent arbitrarily large numbers — there are tasks for these as well.

Prerequisites

• know rounding methods of the class `Math

• know `BigInteger` and `BigDecimal

Data types used in this chapter:

### 1.1. The class Math

The class `Math` contains a large number of mathematical functions, but it is important to also look at wrapper classes, for example, or at the `Scanner` or `Formatter` when it comes to converting a number to a string or parsing a string so that there is a primitive type at the end again.

#### 1.1.1. Quiz: Rule of thumb ⭐

There are different approaches and different kinds of problems for rounding numerical values:

• On the one hand, a floating point number can be converted to an integer,

• on the other hand, the number of decimal places can be reduced for a floating point number.

The Java library supports different possibilities for conversion and rounding, among other things with

• the explicit type conversion `(int) double``int`

• `Math.floor(double)``double`

• `Math.ceil(double)``double`

• `Math.round(double)``long`

• `Math.rint(double)``double`

• `BigDecimal` and `setScale(..)``BigDecimal`

• `NumberFormat`, configured with `setMaximumFractionDigits(…​)`, then `format(…​)``String`

• `DecimalFormat`, configured with `setRoundingMode(…​)`, then `format(…​)``String`

• `Formatter` with a format string, then `format(…​)``String`.

Four of the methods originate from `Math`, but when it comes to very large and precise floating point numbers or string representation, other classes are involved. Since the methods differ slightly in the result, the following task should make these differences clear once again.

• Fill in the following table with the results of the roundings:

`double` value `d``(int) d``(int) floor(d)``(int) ceil(d)``round(d)``(int) rint(d)`

`-2.5`

`-1.9`

`-1.6`

`-1.5`

`-1.1`

`1.1`

`1.5`

`1.6`

`1.9`

`2.5`

#### 1.1.2. Check if Tin Tin cheated on rounding. ⭐

The accountant Tin Tin does the accounting for Captain CiaoCiao of income and expenses. She gets positive and negative floating point values and writes down the total as a rounded integer for a summary at the end. Captain CiaoCiao suspects that Tin Tin is not being completely honest and is pocketing the penny amounts, when she should use commercially rounding. As a reminder, if the number at the first omitted decimal place is a 0, 1, 2, 3, or 4, round down; if it is 5, 6, 7, 8, or 9, round up.

To test his guess, Captain CiaoCiao needs a program that can sum and check different rounding modes.

• Given an array of floating point numbers (positive and negative) and the sum converted to an integer by Tin Tin.

• Captain CiaoCiao wants to find out which rounding was used to form the integer of the sum. Therefore, the elements in the array are to be summed and compared to Tin Tin’s sum. The rounding is done after the numbers are added.

• Implement a method `RoundingMode detectRoundingMode(double[] numbers, int sum)` that gets a `double` array of numbers and the sum of Tin Tin and checks which rounding mode was used.

• To allow the rounding mode to be represented, introduce an enumeration type:

``````enum RoundingMode {
CAST, ROUND, FLOOR, CEIL, RINT, UNKNOWN;
}``````
• The enumeration elements represent different rounding modes:

• `(int)`, that is, a type conversion.

• `(int) Math.floor(double)`

• `(int) Math.ceil(double)`

• `(int) Math.rint(double)`

• `(int) Math.round(double)`

• Which rounding is bad for Captain CiaoCiao and good for Tin Tin? Which variation could Tin Tin use to cheat?

Example:

• The call might look like this:

``````double[] numbers = { 199.99 };
System.out.println( detectRoundingMode( numbers, 200 ) );``````

Notes:

• There is an enumeration type `RoundingMode` in the `java.math` package, but for our case it does not fit the task.

• It may well happen that more than one rounding mode fits — such as when the sum of the floating point values itself gives an integer — then the method is free to choose one of the rounding modes.

### 1.2. Huge and very precise numbers

The classes `java.math.BigInteger` and `java.math.BigDecimal` can be used to represent arbitrarily large integer and floating point numbers.

#### 1.2.1. Calculate arithmetic mean of a large integer ⭐

To calculate the arithmetic mean of two numbers, they are added together and divided by two. This works well if the sum of the two values does not exceed the largest number that can be represented. If there is an overflow, the result is wrong. There are some algorithms in computer science that can handle this problem as well, but we can make it a little easier and take the higher data type in each case. For example, if we want to calculate the mean value of two `int` variables, we convert the two `int` to a `long`, add the numbers, divide and convert back to the `int`. With the `long` data type, there is no larger primitive data type, but the `BigInteger` type can be used well for the case.

• Calculate the arithmetic mean of two `long` values so that there is no overflow and wrong results. The result should be a `long` again.

#### 1.2.2. Number by number over the phone ⭐

A new deal has made Bonny Brain a lot of money. The number is so big that you can’t just announce it over the phone at all; it has to be conveyed in chunks.

• Write a new method `BigInteger completeNumber(int... parts)` that gets a variable number of numbers and returns the big total number at the end.

Example:

• `completeNumber(123, 22, 989, 77, 9)` returns a `BigInteger` with the value `12322989779`.

#### 1.2.3. Develop class for fractions and truncate fractions ⭐⭐

Bonny Brain is trying a new recipe for a rum punch. Fractions like "1/4 liter grape juice" or "1/2 liter rum" keep appearing in the directions for making it. For the party, she prepares 100 servings, and fractions like "100/4 liters" occur. The fractions can be shortened so that Bonny Brain knows, for example, that 25 liters of grape juice must be purchased.

1. Create a new class `Fraction`.

2. Let there be a constructor `Fraction(int numerator, int denominator)` that stores numerator and denominator in `public final` variables.

• Consider whether there can be faulty arguments, which we should report through exceptions.

• Every created fraction should be simplified automatically. Use the `gcd(…​)` method of `BigInteger`, which calculates the greatest common divisor (ggT)_. Remember: The ggT of numerator and denominator is the largest number by which both are divisible. You can simplify the fraction by dividing both numerator and denominator by this number.

• Both numerator and denominator can be negative, but then you can flip the sign so that both values become positive.

• The objects are all supposed to be immutable, and therefore the variables can be `public`, since they are not supposed to be changed after initialization via the constructor. In other words, the class `Fraction` does not contain any setters.

3. Add the constructor `Fraction(int value)`, where the denominator automatically becomes `1`.

4. Implement a method to multiply fractions and detect overflows.

5. Implement a method `reciprocal()` that returns the inverse of a fraction, that is, swaps the numerator and denominator. With the help of this method, the division of fractions can be implemented.

6. `Fraction` shall extend `java.lang.Number` and implement all mandatory methods.

7. `Fraction` shall implement `Comparable`, because fractions can be converted to a decimal number, and decimal numbers have a natural order.

8. `Fraction` shall implement `equals(…​)` and `hashCode()` correctly.

9. Implement a `toString()` method that returns a string as bare as possible. Figure 1. UML diagram of `Fraction`.

### 1.3. Suggested solutions

#### 1.3.1. Quiz: Rule of thumb

Table 1. Different roundings of a floating point number `d` in comparison
value `d``(int) d``(int) floor(d)``(int) ceiling(d)``round(d)``(int) rint(d)`

`-2.5`

`-2`

`-3`

`-2`

`-2`

`-2`

`-1.9`

`-1`

`-2`

`-1`

`-2`

`-2`

`-1.6`

`-1`

`-2`

`-1`

`-2`

`-2`

`-1.5`

`-1`

`-2`

`-1`

`-1`

`-2`

`-1.1`

`-1`

`-2`

`-1`

`-1`

`-1`

`1.1`

`1`

`1`

`2`

`1`

`1`

`1.5`

`1`

`1`

`2`

`2`

`2`

`1.6`

`1`

`1`

`2`

`2`

`2`

`1.9`

`1`

`1`

`2`

`2`

`2`

`2.5`

`2`

`2`

`3`

`3`

`2`

`Math.round(double)` and `Math.rint(double)` differ for `.5` numbers "on the edge":

• `round(double)` rounds commercially. As can be seen in the table, `round(-2.5)`, `round(-1.5)`, `round(1.5)`, and `round(2.5)` round up; the numbers always become larger. If one always rounds up only commercially, this produces small errors, because the procedure is not symmetrical. To be fair, some `.5` would also have to be rounded down; this is where another method comes into play.

• `rint(double)` behaves like `round(double)` for numbers not ending in `.5`, but when ending in `.5` the following rule applies: the last digit to be retained becomes even. This behavior is called symmetric (also mathematical, scientific) rounding, because it rounds up or down in half the cases, respectively.

In summary:

Table 2. rounding method
procedureresult

type conversion `(int) d`

Truncates decimal places of a floating point number.

`floor(d)`

Rounds to the next smaller number against -∞.

`ceil(d)`

Round to the next larger number against +∞.

`round(d)`

Rounds the value according to commercial rules.

`rint(d)`

Rounds `double` values symmetrically/mathematically/scientifically.

#### 1.3.2. Check if Tin Tin cheated on rounding.

Now we come to the question of which rounding is bad for Captain CiaoCiao and good for Tin Tin. The difference between the rounded value and the sum is the difference Tin Tin can pocket. Example: If the total is 222.22 and Tin Tin rounds to 222, there is a difference of 0.22 that Captain CiaoCiao misses and goes into Tin Tin’s pocket. What do the differences look like for the example numbers?

Table 3. Difference from rounding, sum in foot
value `d``d - (int) d``d - floor(d)``d - ceil(d)``d - round(d)``d - rint(d)`

-2.5

-0.5

0.5

-0.5

-0.5

-0.5

-1.9

-0.9

0.1

-0.9

0.1

0.1

-1.6

-0.6

0.4

-0.6

0.4

0.4

-1.5

-0.5

0.5

-0.5

-0.5

0.5

-1.1

-0.1

0.9

-0.1

-0.1

-0.1

1.1

0.1

0.1

-0.9

0.1

0.1

1.5

0.5

0.5

-0.5

-0.5

-0.5

1.6

0.6

0.6

-0.4

-0.4

-0.4

1.9

0.9

0.9

-0.1

-0.1

-0.1

2.5

0.5

0.5

-0.5

-0.5

0.5

Total

0

5

-5

-2

0

We can read that for the numbers Tin Tin chose, she gets the most out of rounding off all the sums, because that makes the numbers smaller, and she gets the difference in each case, whether the numbers are negative or positive.

To the proposed solution:

com/tutego/exercise/math/RoundingModeDetector.java
``````public enum RoundingMode {
CAST, ROUND, FLOOR, CEIL, RINT, UNKNOWN
}

private static RoundingMode detectRoundingMode( double value, int rounded ) {
return rounded == (int) value         ? RoundingMode.CAST :
rounded == Math.round( value ) ? RoundingMode.ROUND :
rounded == Math.floor( value ) ? RoundingMode.FLOOR :
rounded == Math.ceil( value )  ? RoundingMode.CEIL :
rounded == Math.rint( value )  ? RoundingMode.RINT :
RoundingMode.UNKNOWN;
}

public static RoundingMode detectRoundingMode( double[] numbers, int sum ) {
double realSum = 0;
for ( double number : numbers )
realSum += number;
return detectRoundingMode( realSum, sum );
}``````

The proposed solution is composed of two methods. The public method `detectRoundingMode(…​)` sums the elements of the array and calls the private method `detectRoundingMode(double, int)` to determine the actual rounding mode. The method sequentially compares the integer value with the different rounded variants, and if there is a match, the enumeration element is returned. If the totals and the rounded value do not match at all, the return is `RoundingMode.UNKNOWN`.

#### 1.3.3. Calculate arithmetic mean of a large integer

com/tutego/exercise/math/BigIntegerMean.java
``````private final static BigDecimal TWO = BigDecimal.valueOf( 2 );

public static long meanExact( long x, long y ) {
BigInteger bigSum  = BigInteger.valueOf( x ).add( BigInteger.valueOf( y ) );
BigInteger bigMean = bigSum.divide( BigInteger.TWO );
return bigMean.longValue();
}``````

In the first step we build a new object of type `BigInteger` for the parameters `x` and `y` using the factory method `valueOf(long)`. In the second step the sum is built. In the third step the sum is divided by 2. For the division we also have to use a `BigInteger` object for the divisor. Since the divisor is constant, the solution defines its own constant — the class `BigInteger` has constants for 0, 1 and 10, but not for 2.

When averaging integers, there is always the question of rounding. The addition of two even or two odd numbers always results in an even number, but the sum of an even number with an odd number is odd. If odd numbers are divided by two, there is a remainder, and the question is whether to round up or down, round the result to 0, or round to plus or minus infinity — there are quite a few possibilities. The `BigInteger` method `divide(…​)` behaves like the division of two integers, it is rounded towards 0.

The end result is a number, not greater than `Long.MAX_VALUE` and not smaller than `Long.MIN_VALUE`, so converting the number from the `BigInteger` with `longValue()` gives no loss.

#### 1.3.4. Number by number over the phone

com/tutego/exercise/math/SequentialNumbersToOneNumber.java
``````static BigInteger completeNumber( int... parts ) {
StringBuilder bigNumber = new StringBuilder( parts.length * 2 );
for ( int part : parts )
bigNumber.append( part );

return new BigInteger( bigNumber.toString() );
}``````

We can solve the task using strings or math. Using a temporary string the task is easy to solve.

In the first step we run the array, take all the numbers one by one and append them to a `StringBuilder`. If we assume that each number consists on average of two digits, we can estimate approximately how big the result will be; therefore we use the parameterized constructor of `StringBuilder` with a capacity.

After appending all the digits, `StringBuilder` is converted to a `String` and this feeds the constructor of `BigInteger`. Here the actual conversion of the string into a `BigInteger` begins.

Of course, the task can also be solved without a temporary `StringBuilder`. Let us take the call as an example

`completeNumber(123, 22, 989, 77, 9);`

If at the end we want to create the `BigInteger` with `12322989779`, we could first build the `BigInteger` with `123`, then multiply the number with `100` and add `22`, resulting in `12322`. In the next step, we take the result, multiply it by `1000` and add `989`. Then we multiply again by `100`, add `77`, multiply the result by `10` and add `9`. That is, we always multiply the old value by 10n, where n is the number of digits in the coming number.

#### 1.3.5. Develop class for fractions and truncate fractions

com/tutego/exercise/math/Fraction.java
``````import java.math.BigInteger;

public final class Fraction extends Number implements Comparable<Fraction> {

public final int numerator;
public final int denominator;

public Fraction( int numerator, int denominator ) {
if ( denominator == 0 )
throw new ArithmeticException( "denominator of a fraction can't be 0" );

// denominator always positive
if ( denominator < 0 ) {
numerator   = -numerator;
denominator = -denominator;
}

// shortcut if denominator == 1
if ( denominator == 1 ) {
this.numerator   = numerator;
this.denominator = 1;
}
else {
// try to simplify every fraction
int gcd = gcd( numerator, denominator );
// might be 1, but divide anyway
this.numerator   = numerator / gcd;
this.denominator = denominator / gcd;
}
}

private static int gcd( int a, int b ) {
return BigInteger.valueOf( a )
.gcd( BigInteger.valueOf( b ) )
.intValue();
}

public Fraction( int value ) {
this( value, 1 );
}

public Fraction reciprocal() {
return new Fraction( denominator, numerator );
}

public Fraction multiply( Fraction other ) {
return new Fraction( Math.multiplyExact( numerator, other.numerator ),
Math.multiplyExact( denominator, other.denominator ) );
}

@Override
public int intValue() {
return numerator / denominator;
}

@Override
public long longValue() {
return (long) numerator / denominator;
}

@Override
public double doubleValue() {
return (double) numerator / denominator;
}

@Override
public float floatValue() {
return (float) numerator / denominator;
}

@Override
public int compareTo( Fraction other ) {
return Double.compare( doubleValue(), other.doubleValue() );
}

@Override
public boolean equals( Object other ) {
if ( other == this )
return true;
if ( ! (other instanceof Fraction otherFraction) )
return false;

return    numerator   == otherFraction.numerator
&& denominator == otherFraction.denominator;
}

@Override
public int hashCode() {
return numerator + Integer.reverse( denominator );
}

@Override
public String toString() {
return numerator   == 0 ? "0" :
denominator == 1 ? "" + numerator :
numerator + " / " + denominator;
}
}``````

Let’s start with the constructor `Fraction`, which takes the numerator and denominator. The denominator must never be `0`, this is punished with an exception. We could in principle build our own `Exception` class, but an `ArithmeticException` fits well.

Numerator and denominator can be negative or positive, there are four cases:

• `numerator > 0`, `denominator > 0`.

• `numerator < 0`, `denominator > 0`

• `numerator > 0`, `denominator < 0`

• `numerator < 0`, `denominator < 0`

Let us consider two cases:

• If the numerator and denominator are both negative, we can reverse the sign so that both values become positive.

• If the denominator is negative and the numerator is positive, we can shift the sign to the numerator.

Both cases can be handled with a control flow statement that if the denominator is negative, we flip both signs. A negative denominator then becomes positive. If the numerator was also negative, the numerator becomes positive, so a negative numerator and negative denominator thus both become positive. If the denominator was negative and the numerator was positive, we thus shift the sign to the numerator, because the numerator becomes negative.

Numerator and denominator are now prepared, and if the denominator is `1`, then the fraction does not need to be truncated, and we save the following work and leave the constructor, otherwise we continue in the `else` block.

The last part of the constructor deals with the reduction of the fraction. The task briefly explained how to proceed here: we need the greatest common divisor. The constructor delegates here to its own method `gcd(int, int)`, which first builds a `BigInteger` for two numbers, then lets it calculate the greatest common divisor and then returns it as an integer. In our scenario, the parameter types are `int` so the divisor will be smaller in any case, with `intValue()` we read from the `BigInteger`. After the constructor asks for the greatest common divisor, we divide the numerator and denominator by it, initializing our object variables. In principle, gcd could also be 1, so we don`t need a division, but we save this special case distinction here, because a division by `1` is not expensive.

The second constructor takes only one numerator, and in that case the denominator is `1`. We delegate to our own constructor, but in general we can do the storing ourselves, since we don`t need the special treatment for a negative denominator, and the denominator is not `0` either.

The first of the two methods `reciprocal()` creates a new `Fraction` object by turning the denominator into the numerator and the numerator into the denominator. The method `multiply(…​)` multiplies its own numerator with the numerator of the passed object and symmetrically does the same for the denominator. Multiplication quickly produces large numbers and the value range of `int` could be blown up, so `Math.multiplyExact(…​)` makes sure that the product fits into an `int`; otherwise an exception follows.

The next category of methods comes from the base type `Number`. We divide numerator by denominator and return the result at the different methods.

The next method `compareTo(…​)` comes from the `Comparable` interface. We make it simple and calculate the quotient and compare our quotient with the passed fraction.

In the next step we override the method `equals(…​)` and `hashCode()`. A good hash code will return a different hash code if the numerator or denominator changes. The realization of `hashCode()` does this by flipping the bits of the denominator, so if the number of required bits of the numerator and denominator together does not exceed 32 (the number of bits of an `int`), we can detect each change by a different hashcode.

The last method is `toString()`. If the numerator is `0`, we don`t even have to look at the denominator and return the string `0`. If the denominator is `1`, we can return only the numerator. Otherwise, we return the numerator and denominator separated by a fraction bar.

 Java 8 BackportJava 16 introduces pattern variables, which the proposed solution uses at: ``if ( ! (other instanceof Fraction otherFraction) )``Users of earlier Java versions must write instead: ``````if ( ! (other instanceof Fraction) ) return false; Fraction otherFraction = (Fraction) other; return numerator == otherFraction.numerator && denominator == otherFraction.denominator;``````