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;
}
imk
  • 374
  • 6
  • 12
Taher Ali
  • 37
  • 1
  • 2
  • 5
  • What input do you give it to reproduce the issue? – marstran Oct 09 '17 at 09: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. – marstran Oct 09 '17 at 09: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`. – Dorian Gray Oct 09 '17 at 10:09

5 Answers5

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.

Seelenvirtuose
  • 20,273
  • 6
  • 37
  • 66
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.

Procrastinator
  • 2,526
  • 30
  • 27
  • 36
1

Try this

 BigDecimal inputVal = new BigDecimal(value.toString()).setScale(3, RoundingMode.HALF_UP);
Dinh
  • 759
  • 5
  • 16
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.

achAmháin
  • 4,176
  • 4
  • 17
  • 40
0

You can use string value

num = numberFormat.format(new BigDecimal("95.1").divide(new BigDecimal("100")));
imk
  • 374
  • 6
  • 12