BigDecimal and “java.lang.ArithmeticException: Non-terminating decimal expansion”

In one of my recent projects, I had to use java.math.BigDecimal to divide two values. I had to use BigDecimal instead of double as this was a financial application and required the results to be accurate.

However, after running the application, I encountered the following error intermittenly:

Exception in thread "main" java.lang.ArithmeticException: Non-terminating decimal expansion; no exact representable decimal result.

Below is a sample code which illustrates the issue:

package com.jm.client;

import java.math.BigDecimal;

/**
* Test case for "java.lang.ArithmeticException:
* Non-terminating decimal expansion" error with
* BigDecimal.
*
* @author JM
*
*/
public class TestBigDecimal {

public static void main(String[] args) {

String returnVal = TestBigDecimal.divide("1", "5");

System.out.println("Test #1: returnVal = " + returnVal);

returnVal = TestBigDecimal.divide("1", "2");

System.out.println("Test #2: returnVal = " + returnVal);

// Test(#3) will fail as the quotient (returnVal)
//is a non-terminating decimal value.

returnVal = TestBigDecimal.divide("1", "3");

System.out.println("Test #3: returnVal = " + returnVal);
}

/**
* Divide val1 by val2 and return the result as String.
*
* @param val1
* @param val2
* @return value as String
*/
public static String divide(String val1, String val2) {

BigDecimal v1 = new BigDecimal(val1);

BigDecimal v2 = new BigDecimal(val2);

return v1.divide(v2).toPlainString();

}

}

Below is the output:

Test #1: returnVal = 0.2
Test #2: returnVal = 0.5
Exception in thread “main” java.lang.ArithmeticException: Non-terminating decimal expansion; no exact representable decimal result.
at java.math.BigDecimal.divide(Unknown Source)
at com.jm.client.TestBigDecimal.divide(TestBigDecimal.java:34)
at com.jm.client.TestBigDecimal.main(TestBigDecimal.java:20)

Upon some ‘googling’ and looking at the Java Doc for BigDecimal, I found that this happens due to a couple of reasons:
1. The BigDecimal by default always tries to return the exact result of an operation.
2. Due to this, certain division operations like 1 divided by 3, the exact quotient will have an infinitely long decimal expansion. This will cause the division operation to fail and throw the error as described above.

This is also described in the BigDecimal Java Doc quoted below:
“In the case of divide, the exact quotient could have an infinitely long decimal expansion; for example, 1 divided by 3. If the quotient has a nonterminating decimal expansion and the operation is specified to return an exact result, an ArithmeticException is thrown. Otherwise, the exact result of the division is returned, as done for other operations.”

To fix the issue, we need to provide a scale (i.e. the precision) for the quotient and also the rounding mode to the BigDecimal.divide(). In the sample below, I have used a scale of 2 and the rounding mode as RoundingMode.HALF_UP. You can increase the scale if you want a greater precision.

package com.jm.client;

import java.math.BigDecimal;
import java.math.RoundingMode;

/**
* Test case for "java.lang.ArithmeticException:
* Non-terminating decimal expansion" error with
* BigDecimal.
*
* @author JM
*
*/
public class TestBigDecimal {

public static void main(String[] args) {

String returnVal = TestBigDecimal.divide("1", "5");

System.out.println("Test #1: returnVal = " + returnVal);

returnVal = TestBigDecimal.divide("1", "2");

System.out.println("Test #2: returnVal = " + returnVal);

// Test(#3) will now work as we have provided a scale
// and a rounding mode to the divide() method

returnVal = TestBigDecimal.divide("1", "3");

System.out.println("Test #3: returnVal = " + returnVal);

}

/**
* Divide val1 by val2 and return the result as String.
*
* @param val1
* @param val2
* @return value as String
*/
public static String divide(String val1, String val2) {

BigDecimal v1 = new BigDecimal(val1);

BigDecimal v2 = new BigDecimal(val2);

return v1.divide(v2, 2, RoundingMode.HALF_UP).toPlainString();

}

}

The output of the above program now is as desired:

Test #1: returnVal = 0.20
Test #2: returnVal = 0.50
Test #3: returnVal = 0.33

About these ads
This entry was posted in Java and tagged , . Bookmark the permalink.

54 Responses to BigDecimal and “java.lang.ArithmeticException: Non-terminating decimal expansion”

  1. WALE says:

    THIS IS GREAT AND IT WAS REALLY HELPFUL the problem of bigdecimal rounding up was never as this clear to me

  2. Sathish Kumar says:

    Hi
    Really great, it’s really useful for me.

  3. Alex says:

    Great trick! This helped, thank you very much!

  4. Cheryl Sanders says:

    Awesome! This helped me a great deal and saved me time in researching. Many many thanks!

  5. nkem Uwaje says:

    this was very very helpful. thx for the post.

  6. Aaron says:

    Very helpful post, many thanks, but maybe ditch the snowflakes – they were really making it hard to concentrate on the code.

    Thanks again.

    • jaydeepm says:

      Aaron,

      Glad to hear that the post was helpful to you. Yes, I too realised that the snow is more of a distraction. Will disable the same.

      Cheers,
      Jaydeep

  7. Paul says:

    Great post.

    I have 2 questions:

    An on real-life application, what we must use ? I mean, I work with guys with srtong business knowledge but poor java experience.
    Where can We find more than “tricks” and “java magics” issues ?
    Thanks.

  8. Sven says:

    cheers was most usefull

  9. Slavi says:

    Thanks this was really helpful

  10. Alberto Ngai says:

    Found your page through google and saved me a lot of time.

    Thanks!

  11. nikhil says:

    Thanks. That helped!

    -nik

  12. Mohan says:

    Very good and useful tip to learn. Thanks a lot. Keep up the good work.

  13. Brian says:

    Dude, thanks so much!

  14. Kamlesh says:

    Thanks a lot! This saved my time.

  15. tmumcom says:

    Man, thanks so much, really, your post is the best. saved me! thanks again

  16. Pingback: Back to Java « Coding the markets

  17. zakrom says:

    Really helpful thx

  18. karl pullu says:

    thanks a lot for your help

  19. David says:

    Thanks, that was very useful for me! :D

  20. Sirisha says:

    Thanks,it have saved my time.

  21. Paulo says:

    Thanks a lot, I really didn’t know what was the problem until I saw this great post.

  22. Kristiyan Velinov says:

    Thank you for the good article. It was helpful.

  23. Tim says:

    Exactly what I was looking for. Thanks!

  24. Zac says:

    Thanks! Great work!

  25. withheld says:

    Thanks, saved us in a production issue! Awesome!

  26. HP6 6FB says:

    nice atricle dude , thanks..

  27. Another way to do it. You can contain it to 32, 64 and 128 bits.
    resizeWidth = resizeHeight.divide(ratio, MathContext.DECIMAL32);

  28. gingerdin says:

    thanks, really helped!

  29. Darryl says:

    Thanks a ton!

  30. Amel says:

    saved my day thanks a lot :)

  31. Prasanna says:

    A great post. This was really helpful.

  32. Sriram Viswanathan says:

    Thanks a lot. Just what I needed.

  33. Greg says:

    Yup, great stuff

  34. Always good to find a correct answer on the first search.
    Nicely done, Jay!

  35. ggg says:

    thanx mate ;)

  36. Pingback: Blog: BigDecimal and “java.lang.ArithmeticExce... | Oracle and Java | Syngu

  37. Jorge says:

    Helped me solve my exception, thanks a lot!

  38. cbmeeks says:

    I swear to Christ I’ve been programming for 20+ years in different languages and I’ve never run across an example where a rookie Java developer (me) could get an exception because some import data we had divided 1 by 3 and the fact that it has an infinite repeating value causes an exception. Yes, I get it. I understand it. And I know now how to fix it. But it seems only Java (or the annoying BigDecimal) has a problem with this. Yet one more thing I have to remember. Sorry, just ranting. Really poor day today. Feel silly that I didn’t catch it sooner but like I said, it just seems Java is this way. Don’t ever remember doing this in .NET or Ruby.

    /end of rant…

  39. 234Tiger says:

    I crashed by 50.000 / 106, solution was this:

    public static BigDecimal divide( BigDecimal pZahl1, BigDecimal pDivisor )
    {
    try
    {
    return pZahl1.divide( pDivisor );

    } catch ( ArithmeticException e )
    {
    // java.lang.ArithmeticException: Non-terminating decimal expansion; no exact representable decimal result.
    }

    // if ( divisor.signum() == 0 )
    // { // x/0
    // if ( this.signum() == 0 )
    // { // 0/0
    // throw new ArithmeticException( “Division undefined” ); // NaN
    // }
    // throw new ArithmeticException( “Division by zero” );
    //
    // }

    /*
    * Wenn es nicht anders geht, dann eben über die double Version
    */
    return new BigDecimal( “” + pZahl1.doubleValue() / pDivisor.doubleValue() );
    }

  40. H Evans says:

    An excellent article, concise and to the point and it’s great to see a COMPLETE code example, crucially with the imports at the top.

  41. sri says:

    Really the explanation was clear and helpful. Thanks

  42. Benjamin says:

    Thanks for the blog post. This helped me quickly solve my problem

  43. Arnold says:

    Thank you! This helped me.

  44. Srinivas says:

    Thanks a lot for your post :). Very useful.

  45. Anna says:

    thank you lot,
    was really helpfull and saved me a bunch of time.

  46. Bubbles says:

    This post helped me save a lot of time and get on with the more critical parts of my project. Thanks.

  47. Issam says:

    Merci ! many Thanks

  48. Dev says:

    Thank you.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s