Java double Explained: Range, Precision, Common Pitfalls, and BigDecimal Alternatives

目次

1. What Is Java’s double Type?

Java’s double type is a fundamental data type for working with decimal values. Unlike int or long, which represent integers, double is used to represent numbers with a decimal point such as “1.5,” “3.14,” or “0.01.” It is one of the most frequently used types when performing numeric calculations in Java.

Because beginners often stumble here early on, it’s important to first understand what kind of characteristics double has.

1.1 double Is “Double-Precision Floating-Point”

double is a double-precision floating-point number that represents values using 64 bits (8 bytes).
As the term “floating-point” suggests, double internally handles numeric values as approximations.

As a result, it has the following characteristics:

  • It can handle an extremely wide range of values
  • It can perform calculations involving fractional parts
  • However, it cannot represent every decimal value exactly

The fact that it “cannot represent every decimal exactly” is explained in detail later, but keeping in mind that double is not万能 makes the rest much easier to understand.

1.2 A Practical Picture of What double Can Represent

The range of values a double can represent is extremely large. Roughly speaking, it can handle:

  • Very small numbers (e.g., 0.0000000001)
  • Very large numbers (on the order of 10^300)
  • Typical everyday decimal numbers

For example, all of the following values can be stored in a double:

double a = 3.14;
double b = 0.1;
double c = 123456789.987;

For calculations such as everyday numeric processing, physical quantities, statistical data, and coordinate computations—where “approximately correct is good enough”double is commonly used as the standard choice.

1.3 In Java, Decimal Literals Default to double

In Java, when you write a numeric literal with a decimal point, it is treated as a double by default unless you specify otherwise.

double x = 1.23;   // OK
float  y = 1.23;   // コンパイルエラー

In the example above, float y = 1.23; fails because 1.23 is interpreted as a double.
If you want it to be treated as a float, you must explicitly specify it like this:

float y = 1.23f;

This behavior shows that in Java, double is the default for decimal calculations.

1.4 Common Situations Where double Is Used

double is commonly used in situations like the following:

  • When you want a division result as a decimal
  • Calculations such as averages and ratios
  • Graph rendering and coordinate computations
  • Scientific computing and statistical processing

On the other hand, it is not suitable for money calculations or strict decimal processing.
This is explained later in detail as part of how to choose between double and BigDecimal.

1.5 Key Points to Remember First

To summarize what you’ve learned so far in a beginner-friendly way:

  • double is the basic type for decimal numbers
  • Internally, calculations use approximate values
  • In Java, decimal literals default to double
  • You must be careful when precision matters

2. double Range and Precision (A Guide to Significant Digits)

When learning the double type, one unavoidable topic is the question of “how accurately can it represent numbers?”
In this section, you’ll learn the numeric range, precision, and the idea of significant digits for double in a beginner-friendly way.

2.1 The Numeric Range double Can Represent

Because double uses 64 bits to represent values, it can handle an extremely wide range of numbers.

Conceptually, the range looks like this:

  • Very small numbers:
    e.g., down to around 4.9 × 10^-324
  • Very large numbers:
    e.g., up to around 1.8 × 10^308

In everyday programming, you rarely need to think about these limits.
For most practical purposes, you can consider it as handling an almost “near-infinite” range.

2.2 Significant Digits Are Roughly 15 to 17 Digits

The key concept for understanding double precision is significant digits.

A double is often said to be able to store about 15 to 17 digits accurately.

For example, consider the following values:

double a = 123456789012345.0;
double b = 1234567890123456.0;
  • a (15 digits) can be represented accurately
  • b (16+ digits) may have lower digits rounded off

In other words, as the number of digits grows, fine-grained accuracy is gradually lost.

2.3 “High Precision” Does Not Mean “Exact Decimals”

Here is a common beginner misunderstanding.

double has high precision
→ so it can handle decimals exactly

This is not always correct.

double is indeed a high-precision type, but that means:
“it can be accurate as an approximation up to a certain number of digits”
rather than “every decimal value is exact.”

For example, consider this calculation:

double x = 0.1 + 0.2;
System.out.println(x);

Many people expect 0.3, but in reality you might see something like:

0.30000000000000004

This is not a bug. It is how double works.
The reason is that 0.1 and 0.2 cannot be represented exactly in binary.

2.4 Why Significant Digits Matter

If you don’t understand significant digits, you can run into issues like:

  • Results being slightly off
  • Comparisons with == not matching
  • Errors accumulating in sums or averages

All of these come from the fact that double is a type that handles approximate values.

On the flip side, in areas where “perfect equality” matters less than “realistic precision,” such as:

  • Graph rendering
  • Physical simulations
  • Statistical processing

double is an excellent choice.

2.5 Correct Understanding Based on Range and Precision

To summarize:

  • double can represent an extremely wide range of values
  • It has about 15–17 significant digits
  • Decimals are handled as approximations
  • Be careful when strict precision is required

3. Differences Between double and float (Which Should You Use?)

When working with decimals in Java, double and float are almost always compared.
Both can represent fractional values, but there are major differences in precision, use cases, and practicality.

In this section, we focus on clear decision criteria so beginners don’t get stuck.

3.1 The Basic Differences Between float and double

Let’s keep the comparison simple:

TypeBitsTypical PrecisionMain Use
float32-bitAbout 6–7 digitsLightweight / lower precision
double64-bitAbout 15–17 digitsStandard / higher precision

As you can see, double provides dramatically higher precision.

3.2 Why double Is the Standard in Java

In Java, decimal literals (like 1.23) are treated as double by default.
This is mainly because:

  • On modern CPUs, the performance cost of double is usually negligible
  • Bugs caused by insufficient precision tend to be more serious
  • double is better for readability and safety in typical code

Therefore, in Java, the common approach is: use double unless you have a strong reason not to.

3.3 When You Should Use float

So is float useless?
No—it can be effective depending on the context.

Typical situations where float is chosen include:

  • When you need to minimize memory usage extremely
  • When handling massive numeric arrays (e.g., image processing)
  • When prioritizing speed over precision in games or 3D calculations

However, for business applications or web applications,
there is rarely a strong reason to use float.

3.4 A Simple Rule for Beginners

If you’re unsure which one to use, remember this rule:

  • If in doubt, use double
  • Use float only when memory/performance constraints are strict

Especially while learning, it’s usually more efficient to avoid float-specific precision issues and build understanding with double.

3.5 Why Understanding This Difference Matters

Knowing the difference helps in situations like:

  • Understanding the intent when reading someone else’s code
  • Preventing unnecessary loss of precision
  • Avoiding numeric-calculation bugs before they happen

4. Basic Usage of double (Declaration, Calculation, Output)

Now let’s confirm the basic usage of double with actual code.
If you understand the flow of “declare → calculate → output,” you’ve got the fundamentals covered.

4.1 Declaring and Assigning a double

You declare a double the same way as other primitive types:

double x = 1.5;
double y = 2.0;

When assigning decimal values, you don’t need any special suffix.
You can also assign an integer value; it will be automatically converted to double.

double a = 10;   // Treated as 10.0

4.2 The Four Basic Arithmetic Operations

With double, you can directly use addition, subtraction, multiplication, and division:

double a = 5.0;
double b = 2.0;

double sum = a + b;      // addition
double diff = a - b;     // subtraction
double product = a * b;  // multiplication
double quotient = a / b; // division

All results are also double, so you can naturally handle decimal outcomes.

4.3 A Key Caution with Division

The key point is that division becomes a decimal calculation only if at least one side is a double.

double result1 = 1 / 2;    // result is 0.0
double result2 = 1 / 2.0;  // result is 0.5

1 / 2 uses integers on both sides, so it performs integer division first.
To avoid this, do one of the following:

  • Make one operand a double
  • Use an explicit cast
double result = (double) 1 / 2;

4.4 Printing Calculation Results

You can print a double value directly using System.out.println():

double value = 3.14159;
System.out.println(value);

However, printing as-is may show more digits than you want.

4.5 Printing with a Fixed Number of Digits

If you want cleaner output, printf is convenient:

double value = 3.14159;
System.out.printf("%.2f%n", value);

This prints the value with two digits after the decimal point.

  • %.2f: 2 digits after the decimal point
  • %n: newline

For user-facing displays, it’s recommended to always control the number of displayed digits.

4.6 Summary of double Calculation Basics

Key takeaways from this section:

  • double supports decimal calculations naturally
  • Be careful with division between integers
  • Control displayed digits when printing results

5. Common Pitfall #1: Why Precision Errors Happen

One of the first confusing experiences when using double is:
“the result doesn’t match what I expected.”

This is not a Java bug. It is a core property of the double type.

5.1 A Classic Example of a Precision Error

Let’s look at a well-known example:

double x = 0.1 + 0.2;
System.out.println(x);

Many people expect 0.3, but you may actually see:

0.30000000000000004

Seeing this, you might think “something is wrong” or “is this a bug?”
But this is the correct result for double.

5.2 Why This Kind of Error Occurs

The reason is that double represents numbers using binary.

Humans use base-10, but computers internally use base-2.
The key problem is:

  • Many base-10 decimals cannot be represented with a finite number of binary digits
  • So the system stores the closest approximation

0.1 and 0.2 do not terminate in binary, so they are stored as values that are “very close” but not identical to the exact decimal values.

Adding those approximations produces a result like 0.30000000000000004.

5.3 Always Assume Errors Can Happen

The most important mindset is:

With double, precision errors are unavoidable

Errors become especially noticeable in cases such as:

  • Repeating additions/subtractions many times
  • Calculations that involve division
  • When you need strict correctness down to many decimal places

In short, double is not designed for “perfectly exact decimals.”

5.4 When Errors Usually Don’t Matter

On the other hand, there are many cases where precision errors are rarely a practical problem.

For example:

  • Graphing and animation
  • Sensor values and statistical data
  • Scientific computing
  • Games and simulations

In these areas, what matters more than exact equality is being able to compute with realistic precision.

That’s where double shines.

5.5 How You Should Handle Precision Errors

Trying to eliminate errors completely often breaks your design.
Instead, follow these principles:

  • Accept that errors “can happen”
  • Use appropriate comparison/judgment methods
  • Use different approaches when errors are not acceptable

6. Common Pitfall #2: Using “==” to Compare double Values Is Dangerous

After understanding precision errors, the next issue almost everyone encounters is:
“Why doesn’t comparison work as expected?”

A very common beginner mistake is comparing double values using ==.

6.1 What Happens When You Use “==”

Consider the following code:

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

System.out.println(a == b);

Intuitively, you might expect true, but the result can be false.
This is caused by the precision error explained earlier.

  • a is close to 0.30000000000000004
  • b is a different approximation representing 0.3

Because these values are not identical at the bit level, == reports them as different.

6.2 The Golden Rule for Comparing double Values

There is one fundamental rule you should always remember:

Never compare double values for exact equality

The == operator checks whether the internal representations are exactly the same, not whether the values are “close enough.”

This makes it unsuitable for floating-point numbers.

6.3 Comparing with an Epsilon (Tolerance)

When comparing double values, you should define a threshold for
“how close is close enough.”

This threshold is called an epsilon (tolerance).

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

double epsilon = 1e-9;

if (Math.abs(a - b) < epsilon) {
    System.out.println("Approximately equal");
}

This approach checks whether:

  • The absolute difference is sufficiently small
  • The values can be considered equal for practical purposes

6.4 How Do You Choose an Epsilon?

A common beginner question is:
“How large should epsilon be?”

The idea is simple. Base it on:

  • The scale of the values you are handling
  • The amount of error you can tolerate

Typical rules of thumb include:

  • 1e-9: safe for many general calculations
  • 1e-12: very strict
  • 1e-6: suitable for display or rough estimates

There is no single correct value.
Choose based on your use case.

6.5 How This Differs from BigDecimal

Looking ahead slightly, note the difference in philosophy:

  • double: work while tolerating small errors
  • BigDecimal: design that allows no error

If comparison feels “too complicated,” it may be a sign that double is not the right choice for that task.

6.6 Summary of Comparison Rules

  • Do not use ==
  • Compare using absolute differences
  • Choose epsilon based on context
  • Use other types if strict accuracy is required

7. Common Pitfall #3: Integer Division Produces Zero

Even when using double, you may see results unexpectedly become 0.
This is one of the most common beginner mistakes.

The cause is simple: the calculation is performed using integers.

7.1 Why Integer Division Happens

In Java, the types of the operands determine how a calculation is performed.
Consider this code:

double result = 1 / 2;
System.out.println(result);

The output is:

0.0

Because both 1 and 2 are int, Java performs integer division first, producing 0, which is then converted to double.

7.2 How to Perform Decimal Division Correctly

Avoiding integer division is easy.
Make at least one operand a double.

double result1 = 1 / 2.0;
double result2 = 1.0 / 2;
double result3 = (double) 1 / 2;

All of these produce:

0.5

7.3 A Common Real-World Mistake

This kind of code is often seen in real applications:

int total = 5;
int count = 2;

double average = total / count;

Although it looks correct, the result is 2.0.
The correct way to compute the average is:

double average = (double) total / count;

7.4 Rules Beginners Should Remember

  • Always pay attention to types in division
  • Integer ÷ integer produces an integer
  • Receiving the result as double is not enough

7.5 Summary of the Integer Division Trap

  • The cause is operand types and evaluation order
  • Use double from the start of the calculation
  • Be especially careful with averages and ratios

8. Converting Between Strings and double (Most Common in Practice)

In real-world applications, you rarely hard-code double values.
Much more often, you need to convert strings (String) to numbers.

Typical examples include:

  • Form input values
  • CSV or JSON files
  • Configuration files
  • API responses

This section explains safe ways to convert between String and double.

8.1 Converting a String to double

8.1.1 Double.parseDouble()

The most common and basic method:

String text = "3.14";
double value = Double.parseDouble(text);

If the string is a valid number, conversion succeeds.

8.1.2 Handling Invalid Strings

If the string is not numeric, an exception is thrown:

String text = "abc";
double value = Double.parseDouble(text); // throws exception

This throws a NumberFormatException.
In practice, always use try-catch:

try {
    double value = Double.parseDouble(text);
} catch (NumberFormatException e) {
    // error handling
}

8.2 Difference Between Double.valueOf()

Double.valueOf() is another method for converting a string to a numeric value.

Double value = Double.valueOf("3.14");

The difference between the two methods is:

  • parseDouble → returns a primitive double
  • valueOf → returns a Double wrapper object

For normal numeric calculations, parseDouble is sufficient.
When working with collections such as List<Double>, valueOf is commonly used.

8.3 Converting double to String

Converting a double to a string is also very common.

double value = 3.14;
String text = String.valueOf(value);

Another widely used option is:

String text = Double.toString(value);

Both approaches are safe. Choose based on style or project conventions.

8.4 Always Format Strings for Display

When showing numbers to users,
always use formatted output.

double value = 3.14159;
String text = String.format("%.2f", value);

This formats the value to two decimal places.

8.5 Key Points for String Conversion

  • Always expect invalid input and handle exceptions
  • Separate internal calculations from display formatting
  • Always control decimal places when displaying values

The next section explains special double values: NaN and Infinity.
Without understanding them, debugging numeric issues becomes very difficult.

9. Special Values in the Double Class (NaN / Infinity)

The double type includes special values that are not ordinary numbers.
Understanding them is essential for robust programs.

9.1 What Is NaN (Not a Number)?

NaN represents an undefined numeric result.
It occurs in calculations such as:

double value = 0.0 / 0.0;
System.out.println(value);

The output is:

NaN

9.2 What Is Infinity?

When a division result overflows, Java produces Infinity.

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

The output is:

Infinity

If the numerator is negative, the result is -Infinity.

9.3 How to Check for NaN and Infinity

These values cannot be reliably checked using ==.
Always use the dedicated methods:

double value = 0.0 / 0.0;

if (Double.isNaN(value)) {
    System.out.println("Value is NaN");
}

if (Double.isInfinite(value)) {
    System.out.println("Value is infinite");
}

9.4 Why Early Detection Matters

If NaN or Infinity propagates through calculations, it can cause:

  • All subsequent results becoming NaN
  • Invalid values shown in the UI
  • Broken application logic

Detect abnormal values as early as possible.

10. Use BigDecimal for Money and Exact Calculations

As shown so far, double is very convenient,
but it cannot completely avoid precision errors.

Therefore, it is unsuitable for:

  • Money calculations
  • Point or balance management
  • Strict rounding requirements

10.1 What Is BigDecimal?

BigDecimal is a class that handles decimal numbers exactly in base 10.
It is designed to avoid precision loss.

BigDecimal a = new BigDecimal("0.1");
BigDecimal b = new BigDecimal("0.2");

BigDecimal result = a.add(b);
System.out.println(result); // 0.3

10.2 Important Rule When Using BigDecimal

Creating a BigDecimal directly from a double carries over precision errors.

new BigDecimal(0.1); // Not recommended

Always create it from a string instead:

new BigDecimal("0.1"); // Correct

10.3 Choosing Between double and BigDecimal

  • Performance and simplicity → double
  • Accuracy above all else → BigDecimal

Do not force everything into one type.
Choose based on the purpose.

11. Summary: Using Java double Correctly

Let’s summarize the key points of this article:

  • double is Java’s fundamental decimal type
  • Precision errors are part of the specification
  • Use tolerances for comparison
  • Watch out for integer division
  • Use BigDecimal for exact calculations

Once you understand how double works,
numeric programming becomes far less intimidating.

12. Frequently Asked Questions (FAQ)

Q1. How many digits are accurate in Java double?

About 15–17 significant digits. Decimal values are handled as approximations.

Q2. Should I use double or float?

In most cases, use double unless you have a strong reason to choose float.

Q3. Is it bad to use double for money?

Yes. It is not recommended. Use BigDecimal for safe money calculations.

Q4. Can I use “==” to compare double values?

No. Use a tolerance (epsilon) instead.

Q5. How should I handle NaN and Infinity?

Use Double.isNaN() and Double.isInfinite() to detect them early and handle them explicitly