Can we use double to store money fields and use BigDecimal for arithmetic

I know the problem with double / float and recommended using BigDecimal instead of double / float to represent money fields. But double / float is more efficient and saves space. Then my question is: Is it acceptable to use double / float to represent currency fields in a Java class, but use BigDecimal to perform arithmetic (i.e., convert double / float to BigDecimal before any arithmetic) and is it equal to check?

The reason is to save some space. And I really see that many projects use double / float to represent money fields.

Is there any mistake for this? Thanks in advance.

+2
java double bigdecimal
Dec 6 '11 at
source share
6 answers

No, you can’t.

Suppose double enough to hold two values x and y . Then you convert them to safe BigDecimal and several of them. The result is correct, however if you save the multiplication result in double , most likely you will lose accuracy. Evidence:

 double x = 1234567891234.0; double y = 1234567891234.0; System.out.println(x); System.out.println(y); BigDecimal bigZ = new BigDecimal(x).multiply(new BigDecimal(y)); double z = bigZ.doubleValue(); System.out.println(bigZ); System.out.println(z); 

Results:

 1.234567891234E12 //precise 'x' 1.234567891234E12 //precise 'y' 1524157878065965654042756 //precise 'x * y' 1.5241578780659657E24 //loosing precision 

x and y are exact as well as multiplication using BigDecimal . However, after returning to double we lose the least significant digits.

+5
Dec 06 2018-11-12T00:
source share

long would be a much better choice than double / float .

Are you sure that using BigDecimal will become a real bottleneck?

+2
Dec 06 2018-11-12T00:
source share

Which is acceptable depends on your project. You can use double and long in some projects, as you might expect. However, in other projects this is considered unacceptable. Twice, you can represent values ​​of up to 70,000,000,000,000.00 per cent (more than the US national debt), with a fixed place that you can accurately determine at 90,000,000,000,000,000,000.00.

If you have to deal with hyperinflationary currencies (a bad idea anyway), but for some reason you still need to consider every cent, use BigDecimal.

If you use double or long or BigDecimal, you must round the result. How you do this depends on each data type, and BigDecimal is the least error prone, since you need to specify what rounding and precision for different operations. With double or long, you stay on your devices.

+2
Dec 06 '11 at 13:23
source share

I would also recommend using nothing but BigDecimal for ALL arithmetic operations, which may include currency.

Make sure you always use the String BigDecimal constructor. What for? Try the following code in the JUnit test:

 assertEquals(new BigDecimal("0.01").toString(), new BigDecimal(0.01).toString()); 

You get the following result:

 expected:<0.01[]> but was <0.01[000000000000000020816681711721685132943093776702880859375]> 

In truth, you cannot store EXACTLY 0.01 as a “double” amount. Only BigDecimal saves the number you need EXACTLY how you want it.

And remember that BigDecimal is immutable. The following will compile:

 BigDecimal amount = new BigDecimal("123.45"); BigDecimal more = new BigDecimal("12.34"); amount.add(more); System.out.println("Amount is now: " + amount); 

but the resulting output will be:

Amount now: 123.45

This is because you need to assign the result to a new (or the same) BigDecimal variable.

In other words:

 amount = amount.add(more) 
+2
Dec 13 '11 at 23:17
source share

Drop falling is that float / doubles cannot store all values ​​without loss of precision. Even if you use BigDecimal and maintain accuracy during calculations, you still save the final product as float / double.

The “correct” solution to this, in my experience, is to store monetary values ​​in the form of integers (for example, Long ) representing thousands of dollars. This gives sufficient resolution for most tasks, for example. percentage load, while the side posing the problem of using floats / paired. As an added “bonus”, this requires approximately the same amount of storage as float / doubles.

0
Dec 06 2018-11-12T00:
source share

If you use only double to store decimal values, then yes, you can under certain conditions: if you can guarantee that your values ​​have no more than 15 decimal digits, then convert the value to double (53 bits of precision) and convert double back to decimal with 15-digit precision (or less) will give you the original value, i.e. without any loss, from the application of the theorem of David Matula, proved in his article Transformations "inputs" and "no . " Please note that in order for this result to apply, transformations must be performed with the correct rounding .

Please note, however, that double may not be the best choice: monetary values ​​are usually expressed not in floating point, but at a fixed point with several digits (p) after the decimal point, in which case the conversion of the value to an integer with a scale of 10 ^ p and the preservation of this whole (as suggested by others).

0
Jul 27 '14 at 20:37
source share



All Articles