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
THIS IS GREAT AND IT WAS REALLY HELPFUL the problem of bigdecimal rounding up was never as this clear to me
Hi
Really great, it’s really useful for me.
Great trick! This helped, thank you very much!
Awesome! This helped me a great deal and saved me time in researching. Many many thanks!
was helpful
ty
this was very very helpful. thx for the post.
Very helpful post, many thanks, but maybe ditch the snowflakes – they were really making it hard to concentrate on the code.
Thanks again.
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
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.
cheers was most usefull
Thanks this was really helpful
Found your page through google and saved me a lot of time.
Thanks!
Thanks! Good to know that it was of help to you.
Thanks. That helped!
-nik
Very good and useful tip to learn. Thanks a lot. Keep up the good work.
Dude, thanks so much!
Thanks a lot! This saved my time.
Man, thanks so much, really, your post is the best. saved me! thanks again
Pingback: Back to Java « Coding the markets
Really helpful thx
thanks a lot for your help
Thanks, that was very useful for me! 😀
Thanks,it have saved my time.
Thanks a lot, I really didn’t know what was the problem until I saw this great post.
Thank you for the good article. It was helpful.
Exactly what I was looking for. Thanks!
Thanks! Great work!
Thanks, saved us in a production issue! Awesome!
nice atricle dude , thanks..
Another way to do it. You can contain it to 32, 64 and 128 bits.
resizeWidth = resizeHeight.divide(ratio, MathContext.DECIMAL32);
@Brandon Donnelson : exactly very helpfull , what i was searching for….. thanks a lot
thanks, really helped!
Thanks a ton!
Yay! Thanks!
saved my day thanks a lot 🙂
A great post. This was really helpful.
Thanks a lot. Just what I needed.
Yup, great stuff
Always good to find a correct answer on the first search.
Nicely done, Jay!
thanx mate 😉
Pingback: Blog: BigDecimal and “java.lang.ArithmeticExce... | Oracle and Java | Syngu
Helped me solve my exception, thanks a lot!
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…
BTW, I’m complaining about Java, not this site or the advice. You actually helped me solve an issue quickly. So thanks for that.
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() );
}
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.
Really the explanation was clear and helpful. Thanks
Thanks for the blog post. This helped me quickly solve my problem
Thank you! This helped me.
Thanks a lot for your post :). Very useful.
thank you lot,
was really helpfull and saved me a bunch of time.
This post helped me save a lot of time and get on with the more critical parts of my project. Thanks.
Merci ! many Thanks
Thank you.