What is the difference between new BigDecimal("0.1"), new BigDecimal(0.1), and BigDecimal.valueOf(0.1)?
answer
- String ctor parses text → exact
- double ctor copies the double's binary error → huge scale
- valueOf(double) = new BigDecimal(Double.toString(d)) → safe
- valueOf(long, scale) builds from unscaled integer
- Never pass raw double to the constructor
basics
~10 snew BigDecimal("0.1") is exactly 0.1. new BigDecimal(0.1) takes the imprecise double and copies its error, giving 0.1000000000000000055... BigDecimal.valueOf(0.1) is safe — it produces exactly 0.1.
solid answer
~40 sThe String constructor new BigDecimal('0.1') parses the text directly and stores exactly 0.1 with scale 1 — this is the safe, canonical way. The double constructor new BigDecimal(0.1) is a trap: the double literal 0.1 is already an imprecise binary approximation, and the constructor faithfully captures that full error, producing 0.1000000000000000055511151231257827021181583404541015625 with a huge scale. BigDecimal.valueOf(double) is the recommended way to convert a double — internally it calls Double.toString(d), which gives the short, human-expected decimal, so valueOf(0.1) yields exactly 0.1 with scale 1. Rule of thumb: never pass a raw double into the BigDecimal constructor; use the String constructor for literals you control, and BigDecimal.valueOf when you genuinely start from a double. There is also valueOf(long, scale) for building from an unscaled long.
code
java · 4 linesSystem.out.println(new BigDecimal("0.1")); // 0.1 (scale 1)
System.out.println(new BigDecimal(0.1)); // 0.1000000000000000055511151231257827021181583404541015625
System.out.println(BigDecimal.valueOf(0.1)); // 0.1
System.out.println(BigDecimal.valueOf(12345, 2)); // 123.45go deeper
Knows to use the String constructor for literals and to avoid passing a double into the BigDecimal constructor.
Explains why the double constructor captures the binary error and that valueOf(double) routes through Double.toString to stay safe; knows valueOf(long,scale).
Articulates the exact decision rule across String ctor / valueOf(double) / valueOf(long,scale), and reviews code for the double-ctor antipattern.
Bakes the construction rules into lint/static-analysis (e.g. forbid new BigDecimal(double)) and ORM/serialization config so the pitfall can't reach production.
## Three ways to make a BigDecimal — only one is a trap This is one of the most common BigDecimal interview questions because the wrong choice silently reintroduces the exact floating-point error BigDecimal is meant to eliminate. ### 1. `new BigDecimal("0.1")` — String constructor (safe) The String constructor **parses the characters of the text**. The text `"0.1"` unambiguously means one tenth, so it stores unscaled value `1` with **scale 1** — i.e. exactly 0.1. Use this whenever you have a literal value you control. ### 2. `new BigDecimal(0.1)` — double constructor (the pitfall) The argument `0.1` here is a `double` literal. As covered in the precision question, the double named `0.1` is **not** exactly 0.1 — it is the nearest binary value, about `0.1000000000000000055511151231257827021181583404541015625`. The `BigDecimal(double)` constructor is **faithful**: it captures the *full, exact* value of that imperfect double, error and all. The result has a giant scale (around 55) and is not the 0.1 you wanted: ``` new BigDecimal(0.1) // = 0.1000000000000000055511151231257827021181583404541015625 ``` This is technically "correct" (it is the exact value of the double you passed) but almost never what you intend. The Javadoc explicitly warns about it and recommends the String constructor. ### 3. `BigDecimal.valueOf(0.1)` — the double-to-BigDecimal bridge (safe) `BigDecimal.valueOf(double)` is the **recommended** way to go from a `double`. Internally it does `new BigDecimal(Double.toString(d))`. `Double.toString` produces the **shortest decimal string that round-trips** back to the same double — for `0.1` that is just `"0.1"`. So you get exactly 0.1 with scale 1, the human-expected result. The cost is you lose the "full exact double value" — but that value was a binary artifact you didn't want anyway. ### Bonus: `BigDecimal.valueOf(long, int scale)` There is also `valueOf(long unscaledVal, int scale)` which builds the number directly from an unscaled long and a scale: `BigDecimal.valueOf(12345, 2)` is exactly `123.45`. This is the precise, allocation-light way to construct from integer components, and it's how you'd build money from cents. There are also cached constants `BigDecimal.ZERO`, `BigDecimal.ONE`, and `BigDecimal.TEN` for those common values. ## Decision rule - Literal you typed → **`new BigDecimal("...")`** (String). - You truly have a `double` in hand → **`BigDecimal.valueOf(d)`**. - You have integer components → **`BigDecimal.valueOf(unscaled, scale)`**. - **Never** `new BigDecimal(someDouble)` unless you specifically want the double's exact binary value (rare).
- How does valueOf(double) avoid the error that the constructor keeps?It delegates to new BigDecimal(Double.toString(d)). Double.toString returns the shortest decimal that round-trips to that double, so 0.1 → "0.1", giving the human-expected value with small scale instead of the full binary expansion.
- Is new BigDecimal(0.1) actually wrong, or just surprising?It is not wrong — it faithfully stores the exact value of the double you passed. It's surprising because that double is already an approximation of 0.1. It's the wrong tool, not a bug.
saying these in an interview costs you the question
- Saying valueOf(double) and new BigDecimal(double) are equivalent
- Claiming new BigDecimal(0.1) gives exactly 0.1
- Thinking the double constructor is buggy (it's faithful — the double is the problem)
- Using the String constructor for a value that originates as a double via concatenation pitfalls