杰瑞科技汇

Java中decimal与double有何区别?

Of course! This is a fundamental and very important topic in Java. Here’s a comprehensive breakdown of double and decimal (which is represented by BigDecimal in Java).

Java中decimal与double有何区别?-图1
(图片来源网络,侵删)

The Short Answer

  • double: A primitive data type in Java used for storing 64-bit floating-point numbers. It's fast and memory-efficient but not precise. It's best for general scientific calculations where a small degree of error is acceptable (e.g., physics simulations, graphics).
  • Decimal (Java's BigDecimal): A class in Java used for storing decimal numbers with arbitrary precision. It's precise but slower and uses more memory. It's essential for financial and monetary calculations where accuracy is critical (e.g., currency, taxes, accounting).

Detailed Comparison Table

Feature double BigDecimal
Type Primitive data type Object (Reference Type)
Precision Limited and imprecise. Based on IEEE 754 standard. Cannot represent some decimal fractions (like 0.1) exactly. Arbitrary precision. Can represent numbers with any number of decimal places, limited only by memory.
Performance Very Fast. Operations are handled directly by the CPU's floating-point unit (FPU). Slower. Operations are performed in software using objects and method calls, which have overhead.
Memory Usage Fixed. Always uses 64 bits (8 bytes). Variable. Uses more memory, which grows with the number of digits.
Primary Use Case General-purpose math, science, engineering, graphics where performance is key and precision errors are tolerable. Financial calculations, currency, monetary values, or any application where exact decimal representation is required.
Special Values Can represent Infinity, -Infinity, and NaN (Not a Number). Cannot represent Infinity or NaN. Throws an ArithmeticException for operations like division by zero.
How to Declare double price = 19.99; BigDecimal price = new BigDecimal("19.99");

The Core Problem: Why double is Imprecise

The main reason you need BigDecimal is that double uses a binary (base-2) floating-point representation, while we typically work with decimal (base-10) numbers in daily life.

This leads to a classic and very common issue:

// A classic demonstration of double's imprecision
double a = 0.1;
double b = 0.2;
double sum = a + b;
System.out.println(sum); // Output: 0.30000000000000004
// This is NOT what you want for financial calculations!

Why does this happen? Just like 1/3 is 0.333... in base-10, some simple decimal fractions cannot be represented exactly in a finite binary format. 1 in decimal is a repeating fraction in binary. Java stores the closest possible binary approximation, which leads to tiny rounding errors.


Working with BigDecimal

BigDecimal is the solution, but it requires a different way of thinking. You cannot use the standard , , , operators. You must use its methods.

Java中decimal与double有何区别?-图2
(图片来源网络,侵删)

Creation (Very Important!)

You should always create a BigDecimal from a String. Never from a double, as you would just be transferring the imprecise value from the double into the BigDecimal.

// GOOD: Precise creation from a String
BigDecimal goodValue = new BigDecimal("123.456789");
// BAD: Carries over the imprecision of the double
double d = 123.456789;
BigDecimal badValue = new BigDecimal(d); // Creates an imprecise BigDecimal
System.out.println(badValue); // Might print something like 123.4567890000000045474735088646411895751953125

You can also use BigDecimal.valueOf(double d), which is often a good compromise as it's more efficient than creating from a string but generally more precise than creating directly from a double literal.

// A good alternative
BigDecimal fromDouble = BigDecimal.valueOf(123.456789);

Arithmetic Operations

Use the add(), subtract(), multiply(), and divide() methods.

BigDecimal price1 = new BigDecimal("19.99");
BigDecimal price2 = new BigDecimal("25.50");
BigDecimal taxRate = new BigDecimal("0.08"); // 8% tax
// Addition
BigDecimal total = price1.add(price2);
System.out.println("Total: " + total); // Output: Total: 45.49
// Multiplication
BigDecimal tax = total.multiply(taxRate);
System.out.println("Tax: " + tax); // Output: Tax: 3.6392
// Division
// IMPORTANT: Division can throw an ArithmeticException if the result is non-terminating.
// You MUST specify a rounding mode and scale (number of decimal places).
BigDecimal perPerson = total.divide(new BigDecimal("2"), 2, RoundingMode.HALF_UP);
System.out.println("Per Person: " + perPerson); // Output: Per Person: 22.75

Rounding and Formatting

Since BigDecimal is arbitrary precision, you often need to round it for display or storage.

Java中decimal与double有何区别?-图3
(图片来源网络,侵删)
  • setScale(int scale, RoundingMode mode): This is the most common method for rounding.
    • scale: The number of digits to the right of the decimal point.
    • RoundingMode: How to handle numbers that fall exactly between two values (e.g., 2.5). Common modes are HALF_UP (standard rounding), UP, DOWN, CEILING, FLOOR.
BigDecimal bigDecimal = new BigDecimal("123.4567");
// Round to 2 decimal places, using standard rounding (e.g., 3.5 becomes 4)
BigDecimal rounded = bigDecimal.setScale(2, RoundingMode.HALF_UP);
System.out.println(rounded); // Output: 123.46
// For currency, you almost always want to round to 2 decimal places.
BigDecimal currency = new BigDecimal("99.999");
BigDecimal currencyRounded = currency.setScale(2, RoundingMode.HALF_UP);
System.out.println(currencyRounded); // Output: 100.00

When to Use Which? (A Practical Guide)

Use double when:

  • Performance is critical: You are doing millions of calculations (e.g., in a game engine, a physics simulation, or data analysis).
  • Minor precision errors are acceptable: The application is not dealing with money. For example, a small error in the position of a particle in a game is unnoticeable.
  • ✅ You need to use special values like Infinity or NaN.
// Good use case for double: A game calculating a trajectory
double velocity = 50.5;
double angleInRadians = Math.toRadians(45);
double xVelocity = velocity * Math.cos(angleInRadians);
// A tiny error here is completely fine.

Use BigDecimal when:

  • Accuracy is non-negotiable: This is the #1 rule. If you are dealing with money, prices, financial interest, or any accounting data, you must use BigDecimal.
  • ✅ You need control over rounding and decimal places.
  • ✅ You are reading numbers from a file or a database where precision must be preserved exactly as it was written.
// Good use case for BigDecimal: Calculating an invoice
BigDecimal itemPrice = new BigDecimal("99.99");
BigDecimal quantity = new BigDecimal("2");
BigDecimal discountRate = new BigDecimal("0.10"); // 10% discount
BigDecimal subtotal = itemPrice.multiply(quantity);
BigDecimal discountAmount = subtotal.multiply(discountRate);
BigDecimal total = subtotal.subtract(discountAmount);
// Always round currency to 2 decimal places
total = total.setScale(2, RoundingMode.HALF_UP);
System.out.println("Invoice Total: $" + total); // Output: Invoice Total: $179.98

Conclusion

double BigDecimal
Analogy A fast, but slightly inaccurate, measuring tape. A perfect, laser-based measuring tool.
Takeaway Use double for performance and general math. Use BigDecimal for anything involving money or where exact decimal precision is required.
分享:
扫描分享到社交APP
上一篇
下一篇