BigDecimal Rounding discrepancy using string and (int, long, double) constructors

What is the difference between using different constructors in bigdecimal when using round off. When running the below code:

public class RoundTest {

    /**
     * @param args
     */
    public static void main(String[] args) {//2.425
        BigDecimal intv = new BigDecimal(4.645);
        BigDecimal doublev = new BigDecimal(4.645);
        BigDecimal strV = new BigDecimal("4.645");
        BigDecimal longV = new BigDecimal(4.645);

        System.out.println("Int - "+intv.setScale(2, RoundingMode.HALF_UP));
        System.out.println("Int - "+intv.setScale(2, RoundingMode.HALF_DOWN));
        System.out.println("Int - "+intv.setScale(2, RoundingMode.HALF_EVEN));

        System.out.println("Double -"+doublev.setScale(2, RoundingMode.HALF_UP));
        System.out.println("Double -"+doublev.setScale(2, RoundingMode.HALF_DOWN));
        System.out.println("Double -"+doublev.setScale(2, RoundingMode.HALF_EVEN));

        System.out.println("String - "+strV.setScale(2, RoundingMode.HALF_UP));
        System.out.println("String - "+strV.setScale(2, RoundingMode.HALF_DOWN));
        System.out.println("String - "+strV.setScale(2, RoundingMode.HALF_EVEN));

        System.out.println("Long - "+longV.setScale(2, RoundingMode.HALF_UP));
        System.out.println("Long - "+longV.setScale(2, RoundingMode.HALF_DOWN));
        System.out.println("Long - "+longV.setScale(2, RoundingMode.HALF_EVEN));
    }
}

Output is :

Int - 4.64
Int - 4.64
Int - 4.64
Double -4.64
Double -4.64
Double -4.64
**String - 4.65**
String - 4.64
String - 4.64
Long - 4.64
Long - 4.64
Long - 4.64

Why does round off using string constructor give a different result than the others? Are there any more differences when using rounding off with BigDecimal?

Jon Skeet
people
quotationmark

Why does round off using string constructor give a different result than the others?

Because it's the only time you're actually passing in a value of exactly 4.645. The rest of the time, you're passing in the double value closes to 4.645, which isn't actually 4.645 - it's 4.644999999999999573674358543939888477325439453125.

You can use BigDecimal.valueOf(double) to create the BigDecimal value which effectively parses the double value's canonical string representation instead - then you'd get the same results as for String.

people

See more on this question at Stackoverflow