CodeGym /Courses /JAVA 25 SELF /Precision issues and special values

Precision issues and special values

JAVA 25 SELF
Level 6, Lesson 3
Available

1. Introduction

It may seem that if a computer is “smart”, then 0.1 + 0.2 should simply be 0.3. But that’s not quite the case. Let’s figure it out with a simple example.


double x = 0.1;
double y = 0.2;
double sum = x + y;
System.out.println(sum); // What will the program print?
Adding floating-point numbers: we expect 0.3—what do we actually get?

Now try comparing to 0.3:

System.out.println(sum == 0.3); // Will it be true or false here?

If you see false, don’t be surprised!

The reason lies in how numbers are represented in memory

Computers work with numbers in binary. But not all decimal fractions can be represented as a finite binary fraction, just as 1/3 cannot be written exactly as a decimal (0.333...). For example, 0.1 in binary is an infinite fraction, and it has to be “rounded” for storage.

In plain terms, double sometimes “pretends” to store your number exactly, but in reality it stores only a very close approximation.

2. What kinds of “gotchas” happen with double arithmetic?

Let’s look at practical examples.

Example 1. The classic “0.1 + 0.2 magic”

double a = 0.1;
double b = 0.2;
double sum = a + b;
System.out.println(sum);            // 0.30000000000000004
System.out.println(sum == 0.3);     // false

The computer printed not 0.3 but 0.30000000000000004. The difference is small, but if you’re dealing with, say, finance—this can be critical.

Example 2. Iterative addition

double result = 0;
for (int i = 0; i < 10; i++)
{
    result += 0.1;
}
System.out.println(result); // 0.9999999999999999

We wanted 1.0—got slightly less. Again, the reason is rounding inside double.

Why this matters in real-world tasks

Many think: “What’s the big deal—just a tiny error!” Let’s look at an example from the world of payments.

Suppose your online bank adds up 100 transactions of 0.1 euro each. If your program “loses” one hundred-thousandth of a euro on each iteration, then at bank scale you will already be losing real money. That’s when the accountant will immediately show up and ask: “Where is our money?!”

3. How to compare floating-point numbers correctly

Since double often cannot store exactly the value you expect, direct comparison with == can let you down. Instead, it’s customary to compare the absolute difference of the numbers to a very small number (epsilon).

Example of tolerance-based comparison

double a = 0.1 + 0.2;
double b = 0.3;
double epsilon = 0.000001;

if (Math.abs(a - b) < epsilon)
{
    System.out.println("Almost equal!"); // This comparison is safer
}

Here we say: “If the difference between the numbers is less than one millionth, consider the numbers equal.”
Note: the Math.abs(value) function returns the absolute value (magnitude) of the number passed to it.

4. Special double values: Infinity, NaN, -Infinity

The double type stores not only numbers but also special values. They arise in situations that a mathematician would strictly forbid a typical student to do.

Infinity (Infinity)

What happens if you divide 1 by 0?

double result = 1.0 / 0.0;
System.out.println(result); // Infinity

In Java (and many languages), dividing by 0 for double does not throw an exception! Instead, the result becomes the special value “positive infinity.”

Negative infinity (-Infinity)

If you divide a negative number by 0, you get negative infinity:

double result = -1.0 / 0.0;
System.out.println(result); // -Infinity

“Not a number” (NaN — Not a Number)

If you do something really odd, for example, try to compute the square root of a negative number:

double result = Math.sqrt(-1);
System.out.println(result); // NaN

Or the result of dividing 0.0 / 0.0:

double result = 0.0 / 0.0;
System.out.println(result); // NaN

NaN is “anything that wouldn’t be a number in real life.”

Checking for special values

Java has functions to check for special values:

System.out.println(Double.isInfinite(result));    // true if infinity
System.out.println(Double.isNaN(result));         // true if NaN

Table: How double reacts to unusual operations

Operation Result What is stored in double
1.0 / 0.0
Infinity +∞
-1.0 / 0.0
-Infinity -∞
0.0 / 0.0
NaN Not a number
Math.sqrt(-1)
NaN Not a number

5. Common mistakes when working with floating-point numbers

Error #1: Comparing floating-point numbers with ==
The most common trap: trying to check whether two computed floating-point numbers are equal using a plain comparison. Because of accumulated rounding errors, you will almost always get an unexpected result. Always use a tolerance-based comparison (epsilon).

Error #2: Unexpected NaN and Infinity in calculations
If you don’t guard against division by zero or square roots of negative numbers, your program can produce NaN or Infinity and “contaminate” all subsequent computations. Don’t forget to check suspicious values using Double.isNaN() and Double.isInfinite()—this will help avoid unpleasant surprises.

Error #3: Using NaN as a “marker”
Some beginners use NaN as a “special” value for checks, for example, “if not found—return NaN”. But remember: NaN is tricky, and comparison using == will not work! Check only through the special methods.

Error #4: Expecting an exception when dividing by 0.0
Unlike integer division, division by 0.0 for double does not raise an error but returns Infinity or NaN. This can lead to silent and hard-to-detect bugs—the result exists, but it’s not what you expected.

1
Task
JAVA 25 SELF, level 6, lesson 3
Locked
Check the accuracy of a chemical solution 🧪
Check the accuracy of a chemical solution 🧪
1
Task
JAVA 25 SELF, level 6, lesson 3
Locked
Exploring the limits of the computational universe 🌌
Exploring the limits of the computational universe 🌌
1
Task
JAVA 25 SELF, level 6, lesson 3
Locked
Attempt to compute the Unknown ❓
Attempt to compute the Unknown ❓
1
Task
JAVA 25 SELF, level 6, lesson 3
Locked
High-Precision Laser Calibration 🔬
High-Precision Laser Calibration 🔬
Comments
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION