3
\$\begingroup\$

I need to remove the fractional part of a BigDecimal value when its scale has a value of zero. For example,

BigDecimal value = new BigDecimal("12.00").setScale(2, RoundingMode.HALF_UP);

It would assign 12.00. I want it to assign only 12 to value in such cases.


BigDecimal value = new BigDecimal("12.000000").setScale(2, RoundingMode.HALF_UP);

should assign 12,


BigDecimal value = new BigDecimal("12.0001").setScale(2, RoundingMode.HALF_UP);

should assign 12.


BigDecimal value = new BigDecimal("12.0051").setScale(2, RoundingMode.HALF_UP);

should assign12.01


BigDecimal value = new BigDecimal("12.99").setScale(2, RoundingMode.HALF_UP);

should assign 12.99.


BigDecimal value = new BigDecimal("12.999").setScale(2, RoundingMode.HALF_UP);

should assign13


BigDecimal value = new BigDecimal("12.3456").setScale(2, RoundingMode.HALF_UP);

should assign 12.35 and alike.


I have this question on StackOverflow.

For this to be so, I'm doing the following.

String text="123.008";
BigDecimal bigDecimal=new BigDecimal(text);

if(bigDecimal.scale()>2)
{
    bigDecimal=new BigDecimal(text).setScale(2, RoundingMode.HALF_UP);
}

if(bigDecimal.remainder(BigDecimal.ONE).compareTo(BigDecimal.ZERO)==0)
{
    bigDecimal=new BigDecimal(text).setScale(0, BigDecimal.ROUND_HALF_UP);
}

System.out.println("bigDecimal = "+bigDecimal);

It's just as an example. Is there a better way to do this?

\$\endgroup\$
  • \$\begingroup\$ Besides the content, a +1 for providing the tests. Makes it much easier to get an understanding of the desired functionality \$\endgroup\$ – tb- Mar 25 '13 at 17:23
8
\$\begingroup\$

Is there a better way to do this?

Yes, stripTrailingZeros().

To check your tests:

public static void main(final String[] args) {
    check(truncate("12.000000"), "12");
    check(truncate("12.0001"), "12");
    check(truncate("12.0051"), "12.01");
    check(truncate("12.99"), "12.99");
    check(truncate("12.999"), "13");
    check(truncate("12.3456"), "12.35");
    System.out.println("if we see this message without exceptions, everything is ok");
}

private static BigDecimal truncate(final String text) {
    BigDecimal bigDecimal = new BigDecimal(text);
    if (bigDecimal.scale() > 2)
        bigDecimal = new BigDecimal(text).setScale(2, RoundingMode.HALF_UP);
    return bigDecimal.stripTrailingZeros();
}

private static void check(final BigDecimal bigDecimal, final String string) {
    if (!bigDecimal.toString().equals(string))
        throw new IllegalStateException("not equal: " + bigDecimal + " and " + string);

}

output:

if we see this message without exceptions, everything is ok

\$\endgroup\$
  • \$\begingroup\$ Good to know a precise, concise and recommended way. Thank you. \$\endgroup\$ – Tiny Mar 26 '13 at 5:01
  • \$\begingroup\$ Be careful with this. 10.00 becomes 1E+1, not 10. \$\endgroup\$ – stickfigure Nov 11 '18 at 21:08
  • \$\begingroup\$ @stickfigure and how do I make it 10.00 and not 1E+1 ? \$\endgroup\$ – ionutab Dec 14 '18 at 14:14
  • \$\begingroup\$ Depends on what you want to do? I wanted prettier USD amounts, so I ended up manipulating the toString version (ie cost.endsWith(".00") ? cost.substring(0, cost.length() - 3) : cost). \$\endgroup\$ – stickfigure Dec 14 '18 at 18:50
  • \$\begingroup\$ The proposed solutions passes the given tests. For the new case of 10.00: The result is technically correct, only the printing may be inconvenient. The printing can be changed with DecimalFormat. Depending on the specification, new DecimalFormat("0.00") may be suitable. \$\endgroup\$ – tb- Sep 2 at 16:35

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.