Reputation: 885
I tried the following,
double doubleVal = 1.745;
double doubleVal1 = 0.745;
BigDecimal bdTest = new BigDecimal( doubleVal);
BigDecimal bdTest1 = new BigDecimal( doubleVal1 );
bdTest = bdTest.setScale(2, BigDecimal.ROUND_HALF_UP);
bdTest1 = bdTest1.setScale(2, BigDecimal.ROUND_HALF_UP);
System.out.println("bdTest:"+bdTest); //1.75
System.out.println("bdTest1:"+bdTest1);//0.74 problemmmm ????????????
but got weird results. Why?
Upvotes: 56
Views: 147846
Reputation: 331
various option are available such as:
Double d= 123.12;
BigDecimal b = new BigDecimal(d, MathContext.DECIMAL64); // b = 123.1200000
b = b.setScale(2, BigDecimal.ROUND_HALF_UP); // b = 123.12
BigDecimal b1 =new BigDecimal(collectionFileData.getAmount(), MathContext.DECIMAL64).setScale(2, BigDecimal.ROUND_HALF_UP) // b1= 123.12
d = (double) Math.round(d * 100) / 100;
BigDecimal b2 = new BigDecimal(d.toString()); // b2= 123.12
Upvotes: 0
Reputation: 9512
This will maybe give you a hint on what went wrong.
import java.math.BigDecimal;
public class Main {
public static void main(String[] args) {
BigDecimal bdTest = new BigDecimal(0.745);
BigDecimal bdTest1 = new BigDecimal("0.745");
bdTest = bdTest.setScale(2, BigDecimal.ROUND_HALF_UP);
bdTest1 = bdTest1.setScale(2, BigDecimal.ROUND_HALF_UP);
System.out.println("bdTest:" + bdTest); // prints "bdTest:0.74"
System.out.println("bdTest1:" + bdTest1); // prints "bdTest:0.75"
}
}
The problem is, that your input (a double x=0.745;
) can not represent 0.745 exactly. It actually saves a value slightly lower. For BigDecimals
, this is already below 0.745, so it rounds down...
Try not to use the BigDecimal(double/float)
constructors.
Upvotes: 3
Reputation: 533442
For your interest, to do the same with double
double doubleVal = 1.745;
double doubleVal2 = 0.745;
doubleVal = Math.round(doubleVal * 100 + 0.005) / 100.0;
doubleVal2 = Math.round(doubleVal2 * 100 + 0.005) / 100.0;
System.out.println("bdTest: " + doubleVal); //1.75
System.out.println("bdTest1: " + doubleVal2);//0.75
or just
double doubleVal = 1.745;
double doubleVal2 = 0.745;
System.out.printf("bdTest: %.2f%n", doubleVal);
System.out.printf("bdTest1: %.2f%n", doubleVal2);
both print
bdTest: 1.75
bdTest1: 0.75
I prefer to keep code as simple as possible. ;)
As @mshutov notes, you need to add a little more to ensure that a half value always rounds up. This is because numbers like 265.335
are a little less than they appear.
Upvotes: 2
Reputation: 143
Use BigDecimal.valueOf(double d)
instead of new BigDecimal(double d)
. The last one has precision errors by float and double.
Upvotes: 10
Reputation: 328568
double doubleVal = 1.745;
double doubleVal1 = 0.745;
System.out.println(new BigDecimal(doubleVal));
System.out.println(new BigDecimal(doubleVal1));
outputs:
1.74500000000000010658141036401502788066864013671875
0.74499999999999999555910790149937383830547332763671875
Which shows the real value of the two doubles and explains the result you get. As pointed out by others, don't use the double constructor (apart from the specific case where you want to see the actual value of a double).
More about double precision:
Upvotes: 13
Reputation: 29827
Never construct BigDecimals from floats or doubles. Construct them from ints or strings. floats and doubles loose precision.
This code works as expected (I just changed the type from double to String):
public static void main(String[] args) {
String doubleVal = "1.745";
String doubleVal1 = "0.745";
BigDecimal bdTest = new BigDecimal( doubleVal);
BigDecimal bdTest1 = new BigDecimal( doubleVal1 );
bdTest = bdTest.setScale(2, BigDecimal.ROUND_HALF_UP);
bdTest1 = bdTest1.setScale(2, BigDecimal.ROUND_HALF_UP);
System.out.println("bdTest:"+bdTest); //1.75
System.out.println("bdTest1:"+bdTest1);//0.75, no problem
}
Upvotes: 114