# Floating point roundoff error

Floating point values are numbers with decimals. Java uses the type `double` to represent floating point values.

(Java also has a `float` type; however, it is not featured in the AP CS A Java Subset. Java assumes that decimal literals are of type `double` unless explicitly specified as `float`.)

## Roundoff error example

``````double total = 0.0;

total += 1.99;
total += 2.49;
total += 0.99;

System.out.println(total);
``````

The code above prints: `5.470000000000001`

Mathematically, `1.99 + 2.49 + 0.99` is `5.47`.

This is an example of a roundoff error (also known as a rounding error). Java uses a fixed number of bits to represent the value of a `double`. The precision of mathematical calculations is limited by the number of bits used to represent the values involved.

Beginning programmers often seek to fix roundoff errors. This is not an appropriate approach. Although it is possible to perform floating point operations with arbitrary precision, it is not possible to perform them with inifinite precision.

Roundoff error isn’t fixed. Roundoff error is addressed to ensure that programs work as intended. Approaches to address roundoff error include:

• compare `double` values using a tolerance to account for roundoff error.
• avoid roundoff error by using `int` values instead of `double` values.
• round a result to a specific precision before display it.

## Comparing `double` values using `==`

``````double total = 0.0;

total += 1.99;
total += 2.49;
total += 0.99;

if(total == 5.47)
System.out.println("total is 5.47");
else
System.out.println("total is not 5.47");
``````

The code above prints: `total is not 5.47`

As shown in the previous example, the value of `total` is `5.470000000000001`. The expression `5.470000000000001 == 5.47` evalutes to `false`.

Comparing `double` values using `==` or `!=` is usually a mistake. In most cases, the programmer isn’t interested in whether two `double` values are exactly equal, but rather whether they are close enough.

## Comparing `double` values using a tolerance

``````double total = 0.0;

total += 1.99;
total += 2.49;
total += 0.99;

final double TOLERANCE = 0.009;

if(Math.abs(total - 5.47) < TOLERANCE)
System.out.println("total is close enough to 5.47");
else
System.out.println("total is not close enough to 5.47");
``````

The code above prints: `total is close enough to 5.47`

The code calculates the difference between `total` and `5.47`. If the difference is less than the tolerance, the values are considered close enough. The tolerance is specified by the programmer.

The absolute value of the difference is used to prevent all values of `total` less than `5.47` from causing the condition to evaluate to `true`.

The constant `TOLERANCE` is used to make the code easier to understand and modify.

## Using `int` values instead of `double` values

``````int total = 0;

total += 199;
total += 249;
total += 99;

System.out.println(total);

if(total == 547)
System.out.println("total is 547");
else
System.out.println("total is not 547");
``````

The code above prints:

`547`
`total is 547`

This example uses `int` values instead of `double` values. If the values represented amounts of money, these would represent the amounts in cents instead of in dollars.

Calculations using `int` values do not suffer from roundoff error. Calculations with `int` values are subjet to overflow, which is a diffeent concern.

## Rounding a `double` value before output

### Rounding to the nearest `int`

``````double total = 0.0;

total += 1.99;
total += 2.49;
total += 0.99;

int dollars = (int) (total + 0.5);
System.out.println(dollars);

System.out.println(total);
``````

The code above prints:

`5`
`5.470000000000001`

In this example, `total` is known to be non-negative (`>= 0`). The expression: `(int) (total + 0.5)` rounds the non-negative value of `total` to the nearest `int`.

For negative (`< 0`) values of total, the expression `(int) (total - 0.5)` rounds the value of `total` to the nearest `int`.

Note that the value of total remains `5.470000000000001`.

This technique is featured in the AP CS A Course Description.

### Rounding with `Math.round`

``````double total = 0.0;

total += 1.99;
total += 2.49;
total += 0.99;

int dollars = (int) Math.round(total);
System.out.println(dollars);

System.out.println(total);
``````

The code above prints:

`5`
`5.470000000000001`

`Math.round` returns a `long`. If it is know that the value is within the range of an `int`, the value can be cast to an `int`. `Math.round` works for positive values, negative values, and zero.

`Math.round` is outside the scope of the AP CS A Exam.

### `DecimalFormat` class

``````DecimalFormat formatter = new DecimalFormat("#.##");

double num = 123.45678;
System.out.println(formatter.format(num));
System.out.println(num);

num = 123.4;
System.out.println(formatter.format(num));
``````

The code above prints:

`123.46`
`123.45678`
`123.4`

A `DecimalFormat` object can be constructed with a `String` pattern that specifies how `double` values should be formatted. The pattern `#.##` specifies that the value should be rounded to 2 decimal places.

The `format` method returns a `String` with the argument formatted as specified earlier.

`DecimalFormat` is outside the scope of the AP CS A Exam.

### As currency

``````double total = 0.0;

total += 1.99;
total += 2.49;
total += 0.99;

NumberFormat dollarsFormatter = NumberFormat.getCurrencyInstance();
System.out.println(dollarsFormatter.format(total));
``````

When run on a computer configured to use US dollars, the code above prints:

`\$5.47`

The Java Library includes the `NumberFormat` class. `NumberFormat` can be used to quickly format a `double` value as currency, including adding a currency specifier and rounding.

`NumberFormat` is outside the scope of the AP CS A Exam.