Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Convert double to BigDecimal and set BigDecimal Precision

In Java, I want to take a double value and convert it to a BigDecimal and print out its String value to a certain precision.

import java.math.BigDecimal; public class Main {     public static void main(String[] args) {         double d=-.00012;         System.out.println(d+""); //This prints -1.2E-4          double c=47.48000;         BigDecimal b = new BigDecimal(c);         System.out.println(b.toString());          //This prints 47.47999999999999687361196265555918216705322265625      } } 

It prints this huge thing:

47.47999999999999687361196265555918216705322265625

and not

47.48

The reason I'm doing the BigDecimal conversion is sometimes the double value will contain a lot of decimal places (i.e. -.000012) and the when converting the double to a String will produce scientific notation -1.2E-4. I want to store the String value in non-scientific notation.

I want to have BigDecimal always have two units of precision like this: "47.48". Can BigDecimal restrict precision on conversion to string?

like image 399
c12 Avatar asked Sep 12 '12 19:09

c12


People also ask

Which is more accurate BigDecimal or double?

A BigDecimal is an exact way of representing numbers. A Double has a certain precision. Working with doubles of various magnitudes (say d1=1000.0 and d2=0.001 ) could result in the 0.001 being dropped alltogether when summing as the difference in magnitude is so large. With BigDecimal this would not happen.

Can BigDecimal be converted to double?

math. BigDecimal. doubleValue() is an in-built function which converts the BigDecimal object to a double. This function converts the BigDecimal to Double.

How does BigDecimal compare to double in Java?

Convert the double to a BigDecimal, using rounding, and then use compareTo(). Note that equals() takes into account decimal positions, so compareTo() is safer. You may need to round the BigDecimal as well.

How to assign a double value to BigDecimal?

When assigning the double value to BigDecimal, make sure you have not already lost your precision. Better create BigDecimal from String value. If you already have double with lost precision, get it formatted in String with "%.2f" (for example) before creating BigDecimal for right value.

What does formatted double mean in BigDecimal?

The formatted double demonstrates that it's lost the precision after the third place (the application requires those lower places of precision). How can I get BigDecimal to preserve those additional places of precision?

How to print a double as a decimal?

You want to try String.format ("%f", d), which will print your double in decimal notation. Don't use BigDecimal at all. Regarding the precision issue: You are first storing 47.48 in the double c, then making a new BigDecimal from that double. The loss of precision is in assigning to c. You could do to avoid losing any precision.

How to fix double with lost precision in BigDecimal?

If you already have double with lost precision, get it formatted in String with "%.2f" (for example) before creating BigDecimal for right value. It is extremely important to retain the precision when working with the currencies.


2 Answers

The reason of such behaviour is that the string that is printed is the exact value - probably not what you expected, but that's the real value stored in memory - it's just a limitation of floating point representation.

According to javadoc, BigDecimal(double val) constructor behaviour can be unexpected if you don't take into consideration this limitation:

The results of this constructor can be somewhat unpredictable. One might assume that writing new BigDecimal(0.1) in Java creates a BigDecimal which is exactly equal to 0.1 (an unscaled value of 1, with a scale of 1), but it is actually equal to 0.1000000000000000055511151231257827021181583404541015625. This is because 0.1 cannot be represented exactly as a double (or, for that matter, as a binary fraction of any finite length). Thus, the value that is being passed in to the constructor is not exactly equal to 0.1, appearances notwithstanding.

So in your case, instead of using

double val = 77.48; new BigDecimal(val); 

use

BigDecimal.valueOf(val); 

Value that is returned by BigDecimal.valueOf is equal to that resulting from invocation of Double.toString(double).

like image 90
omnomnom Avatar answered Oct 05 '22 08:10

omnomnom


It prints 47.48000 if you use another MathContext:

BigDecimal b = new BigDecimal(d, MathContext.DECIMAL64); 

Just pick the context you need.

like image 38
Gilberto Torrezan Avatar answered Oct 05 '22 07:10

Gilberto Torrezan