简体   繁体   中英

why BigDecimal doesn't work as I expected?

This is the code and the result in the comments:

I was thinking the numB2 should be 16.7500, numB3 = 16.7500, numB4=16.7 and numB5=16.75. But they are not as I expected. Why?

public void testBigDecimal()
{
    float num = 16.7499924f;

    int digitCount = 4;
    MathContext mContext = new MathContext(digitCount, RoundingMode.UP);
    BigDecimal numB = new BigDecimal(num, mContext);
    System.out.println("16.7499924f with MathContext(precision) of 4 =" + numB.floatValue());// 16.75
    numB.setScale(4, RoundingMode.UP);
    System.out
            .println("16.7499924f with MathContext(precision) of 4 and after setScale of 4 =" + numB.floatValue());// 16.75

    BigDecimal numB2 = new BigDecimal(num);
    System.out.println("16.7499924f without MathContext(precision =" + numB2.floatValue());// 16.749992
    numB2.setScale(4, RoundingMode.UP);
    System.out.println("16.7499924f without MathContext(precision) and after setScale of 4 =" + numB2.floatValue());// 16.749992

    BigDecimal numB3 = new BigDecimal(num);
    numB3.setScale(4, RoundingMode.UP);
    System.out.println("16.7499924f without MathContext(precision) but with setScale of 4 =" + numB3.floatValue());// 16.749992

    BigDecimal numB4 = new BigDecimal(num);
    numB4.setScale(1, RoundingMode.UP);
    System.out.println("16.7499924f without MathContext(precision) but with setScale of 1 =" + numB4.floatValue());// 16.749992

    BigDecimal numB5 = new BigDecimal(num);
    numB5.setScale(2, RoundingMode.UP);
    System.out.println("16.7499924f without MathContext(precision) but with setScale of 2 =" + numB5.floatValue());// 16.749992

}

A BigDecimal is immutable. You're ignoring the result of setScale(). So all you have there are basically noops.

Also, use a string to create your BigDecimal. And don't print it as a float value. You're losing precision when doing that, which is the whole point of using BigDecimal in the first place:

String num = "16.7499924";

int digitCount = 4;
MathContext mContext = new MathContext(digitCount, RoundingMode.UP);
BigDecimal numB = new BigDecimal(num, mContext);
System.out.println("16.7499924f with MathContext(precision) of 4 =" + numB.toPlainString());
numB = numB.setScale(4, RoundingMode.UP);
System.out.println("16.7499924f with MathContext(precision) of 4 and after setScale of 4 =" + numB.toPlainString());

As a BigDecimal is immutable, setScale(4, RoundingMode.UP); returns a new BigDecimal with the scale operation applied, it does not affect the original variable. So substitute the numB.setScale(4, RoundingMode.UP); calls by numB2 = numB2.setScale(4, RoundingMode.UP); and omit BigDecimal numB2 = new BigDecimal(num); as it is useless, since you overwrite it in the next step anyways.

Also, you are using a BigDecimal , but then you convert it to float . This may be imprecise, as the documentation states for floatValue() :

Note that even when the return value is finite, this conversion can lose information about the precision of the BigDecimal value.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM