2

I have below piece of code and my precision is getting lost while converting BigDecimal to String. Any help on this really appreciated.
Expected result : 95.10000000000000%
Actual Result : 95.09999999999999%

public static String getAsString(Object value) 
{
    if (value == null)
        return null;

    if (value.toString().length() == 0)
        return null;

    BigDecimal inputVal = new BigDecimal(value.toString());

    if (inputVal == new BigDecimal(0))
        return "";

    NumberFormat numberFormat = NumberFormat.getPercentInstance(Locale.US);
    numberFormat.setMinimumFractionDigits(14); 
    numberFormat.setMaximumFractionDigits(14);
    if (numberFormat instanceof DecimalFormat) {
        DecimalFormat df = (DecimalFormat) numberFormat;
        df.setNegativePrefix("(");
        df.setNegativeSuffix("%)");
    }

    String num = null;
    num = numberFormat.format(new BigDecimal(95.1).divide(new BigDecimal(100)));

    return num;
}
3
  • What input do you give it to reproduce the issue? Commented Oct 9, 2017 at 9:35
  • 5
    Also, inputVal == new BigDecimal(0) will always fail. No object will ever be the same as a newly created one. Use equals instead. Commented Oct 9, 2017 at 9:36
  • @marstran While you're right about the wrong reference comparision, equals isn't the right thing to use, as equals for BigDecimal.equals takes the scale into account (look at the docs). You should instead use BigDecimal.compareTo. Commented Oct 9, 2017 at 10:09

5 Answers 5

11

With this instance creation

new BigDecimal(95.1)

you are losing some precision. What you actually can do is to use the string constructor:

new BigDecimal("95.1")

Another way for your case is to use the factory methods:

BigDecimal.valueOf(95.1)
BigDecimal.valueOf(100)

Internally these use the string representation of those numbers to create a BigDecimal object.

Sign up to request clarification or add additional context in comments.

Comments

3

In this case using the new BigDecimal(double x) and double as an argument and it happens that doubles can't represent x.xxxx exactly. So x.xxxx is "transformed" to the closest possible double, which is x.0000xxxxxxxxxxxzzzzzzzzzzyyyyy and that's what your BigDecimal shows.

So, here the solution could be you can use the String constructor or the valueOf() method, to create the canonical represent of your doubled value.

By changing your line

num = numberFormat.format(new BigDecimal(95.1).divide(new BigDecimal(100)));

to

num = numberFormat.format(BigDecimal.valueOf(95.1).divide(BigDecimal.valueOf(100)));

or

num = numberFormat.format(new BigDecimal("95.1").divide(new BigDecimal("100")));

should give you the correct result.

Comments

1

Try this

 BigDecimal inputVal = new BigDecimal(value.toString()).setScale(3, RoundingMode.HALF_UP);

1 Comment

It doesn't give the expected result. Check your answer please.
1

You can use setScale and then convert to a String.

I see you want to print 14 digits, so set the scale to 14, and use rounding up.

BigDecimal inputVal = new BigDecimal(95.10000000000000).setScale(14, RoundingMode.UP);

Then call toString and add the % etc.

Comments

0

You can use string value

num = numberFormat.format(new BigDecimal("95.1").divide(new BigDecimal("100")));

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.