634

Why does the following code raise the exception shown below?

BigDecimal a = new BigDecimal("1.6");
BigDecimal b = new BigDecimal("9.2");
a.divide(b) // results in the following exception.

Exception:

java.lang.ArithmeticException: Non-terminating decimal expansion; no exact representable decimal result.
Joachim Sauer
  • 302,674
  • 57
  • 556
  • 614
Jason
  • 12,229
  • 20
  • 51
  • 66

9 Answers9

1027

From the Java 11 BigDecimal docs:

When a MathContext object is supplied with a precision setting of 0 (for example, MathContext.UNLIMITED), arithmetic operations are exact, as are the arithmetic methods which take no MathContext object. (This is the only behavior that was supported in releases prior to 5.)

As a corollary of computing the exact result, the rounding mode setting of a MathContext object with a precision setting of 0 is not used and thus irrelevant. 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, you need to do something like this:

a.divide(b, 2, RoundingMode.HALF_UP)

where 2 is the scale and RoundingMode.HALF_UP is rounding mode

For more details see this blog post.

Community
  • 1
  • 1
DVK
  • 126,886
  • 32
  • 213
  • 327
  • 3
    this works for jasper error too thanks http://community.jaspersoft.com/questions/528968/help-please-adding-two-double-values#comment-807628 – shareef Jun 28 '14 at 10:00
  • 37
    2 is NOT `precision`; it's `scale`. Please see http://docs.oracle.com/javase/7/docs/api/java/math/BigDecimal.html#divide%28java.math.BigDecimal,%20int,%20java.math.RoundingMode%29 – John Manko Sep 23 '15 at 16:20
  • (new BigDecimal(100)).divide(new BigDecimal(0.90), 2,RoundingMode.HALF_UP) – egemen Nov 14 '18 at 06:34
  • @AnandVarkeyPhilips It is the scale. See the [Javadoc](http://docs.oracle.com/javase/7/docs/api/java/math/BigDecimal.html#divide%28java.math.BigDecimal,%20int,%20java.math.RoundingMode%29). Edit rejected. – user207421 May 18 '20 at 08:40
  • @user207421, I accidentally edited it and tried reverting.. But didnt have enough points to delete an edit.... https://meta.stackexchange.com/questions/80933/how-can-i-cancel-an-edit-i-made-on-another-users-question-or-answer – Anand Varkey Philips May 18 '20 at 19:33
  • CAUTION! The problem with just applying some rounding mode is that it also has effect on operations that would normally return a value having a finite number of decimal places. When rounding is used the result is scaled to the scale of a divident.   For example: 1 / 8 will result in 0.125 but if you apply rounding it will be 1. – siefca Mar 12 '21 at 19:04
94

Because you're not specifying a precision and a rounding-mode. BigDecimal is complaining that it could use 10, 20, 5000, or infinity decimal places, and it still wouldn't be able to give you an exact representation of the number. So instead of giving you an incorrect BigDecimal, it just whinges at you.

However, if you supply a RoundingMode and a precision, then it will be able to convert (eg. 1.333333333-to-infinity to something like 1.3333 ... but you as the programmer need to tell it what precision you're 'happy with'.

David Bullock
  • 6,112
  • 3
  • 33
  • 43
80

You can do

a.divide(b, MathContext.DECIMAL128)

You can choose the number of bits you want: either 32, 64 or 128.

Check out this link :

http://edelstein.pebbles.cs.cmu.edu/jadeite/main.php?api=java6&state=class&package=java.math&class=MathContext

zb226
  • 9,586
  • 6
  • 49
  • 79
MindBrain
  • 7,398
  • 11
  • 54
  • 74
23

To fix such an issue I have used the below code

a.divide(b, 2, RoundingMode.HALF_EVEN)

Where 2 is scale. Now the problem should be resolved.

alvonellos
  • 1,009
  • 1
  • 9
  • 27
Prahlad
  • 247
  • 2
  • 2
  • 3
    in addition to the code, some explanation should be provided. – Martin Serrano Mar 26 '15 at 18:29
  • 17
    2 is NOT `precision`; it's `scale`. Please see http://docs.oracle.com/javase/7/docs/api/java/math/BigDecimal.html#divide%28java.math.BigDecimal,%20int,%20java.math.RoundingMode%29 – John Manko Sep 23 '15 at 16:21
  • 6
    RoundingMode.HALF_EVEN is recommended for financial applications. This is what's used in banking – ACV Sep 19 '16 at 19:01
  • For those, who are confused by John Mankos's comment on precision, please see this answer https://stackoverflow.com/questions/4591206/arithmeticexception-non-terminating-decimal-expansion-no-exact-representable – Stimpson Cat Jun 22 '18 at 12:50
7

I had this same problem, because my line of code was:

txtTotalInvoice.setText(var1.divide(var2).doubleValue() + "");

I change to this, reading previous Answer, because I was not writing decimal precision:

txtTotalInvoice.setText(var1.divide(var2,4, RoundingMode.HALF_UP).doubleValue() + "");

4 is Decimal Precison

AND RoundingMode are Enum constants, you could choose any of this UP, DOWN, CEILING, FLOOR, HALF_DOWN, HALF_EVEN, HALF_UP

In this Case HALF_UP, will have this result:

2.4 = 2   
2.5 = 3   
2.7 = 3

You can check the RoundingMode information here: http://www.javabeat.net/precise-rounding-of-decimals-using-rounding-mode-enumeration/

Unmitigated
  • 76,500
  • 11
  • 62
  • 80
6

It´s a issue of rounding the result, the solution for me is the following.

divider.divide(dividend,RoundingMode.HALF_UP);
Jorge Santos Neill
  • 1,635
  • 13
  • 6
3

Answer for BigDecimal throws ArithmeticException

public static void main(String[] args) {
        int age = 30;
        BigDecimal retireMentFund = new BigDecimal("10000.00");
        retireMentFund.setScale(2,BigDecimal.ROUND_HALF_UP);
        BigDecimal yearsInRetirement = new BigDecimal("20.00");
        String name = " Dennis";
        for ( int i = age; i <=65; i++){
            recalculate(retireMentFund,new BigDecimal("0.10"));
        }
        BigDecimal monthlyPension =   retireMentFund.divide(
                yearsInRetirement.divide(new BigDecimal("12"), new MathContext(2, RoundingMode.CEILING)), new MathContext(2, RoundingMode.CEILING));      
        System.out.println(name+ " will have £" + monthlyPension +" per month for retirement");
    }
public static void recalculate (BigDecimal fundAmount, BigDecimal rate){
        fundAmount.multiply(rate.add(new BigDecimal("1.00")));
    }

Add MathContext object in your divide method call and adjust precision and rounding mode. This should fix your problem

Community
  • 1
  • 1
3

Your program does not know what precision for decimal numbers to use so it throws:

java.lang.ArithmeticException: Non-terminating decimal expansion

Solution to bypass exception:

MathContext precision = new MathContext(int setPrecisionYouWant); // example 2
BigDecimal a = new BigDecimal("1.6",precision);
BigDecimal b = new BigDecimal("9.2",precision);
a.divide(b) // result = 0.17
Ojda
  • 39
  • 3
1

For me, it's working with this:

BigDecimal a = new BigDecimal("9999999999.6666",precision);
BigDecimal b = new BigDecimal("21",precision);

a.divideToIntegralValue(b).setScale(2)
Anh Ta
  • 31
  • 2