BigDecimal From Floating-Point Value
ID |
java.bigdecimal_double |
Severity |
high |
Remediation Complexity |
medium |
Remediation Risk |
low |
Remediation Effort |
medium |
Resource |
Code Smell |
Language |
Java |
Tags |
reliability |
Description
Reports new BigDecimal(…) calls whose first argument is a double or float value —
primitive or boxed, including the two-argument BigDecimal(double, MathContext) overload.
Constructing from a String, an int/long, or a BigInteger is exact and is not flagged,
and neither is BigDecimal.valueOf(double).
Rationale
double and float are binary floating-point types: most decimal fractions have no exact
binary representation, so the value stored is already an approximation before BigDecimal
ever sees it. The constructed BigDecimal then carries that approximation forward at full
precision, which is rarely what the caller intended.
double taxRate = 0.1;
BigDecimal rate = new BigDecimal(taxRate); // looks like 0.1, is actually
// 0.1000000000000000055511151231257827021181583404541015625
Remediation
Use BigDecimal.valueOf(double), which converts through the value’s String representation
and so avoids the extra binary-to-decimal drift, or construct directly from a String literal:
double taxRate = 0.1;
BigDecimal rate = BigDecimal.valueOf(taxRate); // exact for the printed value of taxRate
BigDecimal fixed = new BigDecimal("0.10"); // exact, no conversion needed