Reputation: 69920
Executing the following code:
new BigDecimal(0.06 * 3).toString()
returns 0.179999999999999993338661852249060757458209991455078125
instead of 0.18
.
Executing
new BigDecimal(0.06).multiply(new BigDecimal(3)).toString()
returns the same result.
How is this possible?
Upvotes: 32
Views: 5608
Reputation: 39208
As Jon Skeet writes above, the reason why you are getting 0.179999999999999993338661852249060757458209991455078125
instead of 0.18
is because 0.06 * 3
is computed as an IEEE 754 double
and then this double
value is converted to a BigDecimal
.
Even though 0.06
looks simple enough in source code, the number 0.06 is not exactly representable as an IEEE 754 double
, so what 0.06
actually represents is an approximation of 0.06 equal to 0.059999999999999997779553950749686919152736663818359375. The number 0.06 in decimal notation is not exactly representable because the number equals 0b0.000011110101110000101 in binary notation (where bold represents a repeating digit sequence). The computer must truncate this infinite sequence of binary digits, leading to the 0.0599999... approximation.
As I detailed in my answer to Question regarding IEEE 754, 64 bits double?, you can use ARIBAS' decode_float()
function to determine the mantissa and exponent of a floating-point number:
==> set_floatprec(double_float). -: 64 ==> set_printbase(2). -: 0y10 ==> decode_float(0.06). -: (0y11110101_11000010_10001111_01011100_00101000_11110101_11000010_10001111, -0y1000100) ==> set_printbase(10). -: 10 ==> -0y1000100. -: -68 ==> set_floatprec(128). -: 128 ==> 1/2**4 + 1/2**5 + 1/2**6 + 1/2**7 + 1/2**9 + 1/2**11 + 1/2**12 + 1/2**13 + 1/2**18 + 1/2**20. -: 0.11999_98855_59082_03125_00000_00000_00000_00
(**
is exponentiation in ARIBAS).
And we have 0.06 = Σ i = 0..∞ 0.11999988555908203125 / 21 + 20 × i
You can evaluate this series in a computer algebra system such as Maxima:
(%i1) sum ( 0.11999988555908203125 / 2 ^ (1 + 20 * i), i, 0, inf ), simpsum; (%o1) 0.06
http://maxima-online.org/?inc=r760264757
Upvotes: 2
Reputation: 2848
Working better with BigDecimal#valueOf
:
BigDecimal.valueOf(0.06).multiply(BigDecimal.valueOf(3))
prints the correct result 0.18
Upvotes: 1
Reputation: 1500055
You're not multiplying two numbers using BigDecimal
. You're multiplying them using double
arithmetic, and passing the result to the BigDecimal
constructor.
You want:
new BigDecimal("0.06").multiply(new BigDecimal("3")).toString()
Note that you do want the values in strings - otherwise you're using the double
value for 0.06, which isn't exactly 0.06... you've lost information before you start. (You don't really need the string form of 3, but I've done so for consistency.)
For example:
System.out.println(new BigDecimal(0.06));
prints
0.059999999999999997779553950749686919152736663818359375
Upvotes: 50