0

Currently I am writing a program to calculate mathematical constants. However, I am having trouble with rounding BigDecimals. Once it hits a non-terminating decimal (1.6) it throws an error. I think the problem is rounding line, but it sets it too the right number of decimal places, but doesn't round it. I am new to BigDecimals so I probably forgot something. The code and output is shown below. Thanks!

This my code:

package goldenratio;
import java.math.*;

public class GoldenRatio {
static BigDecimal now;
static BigDecimal before;
static BigDecimal phi;
/**
 * @param args the command line arguments
 */
public static void main(String[] args) {
    for(int i=1;i<=100;i++)
    {
        if(i==1)
        {
            now=BigDecimal.valueOf(1);
            before=BigDecimal.valueOf(1);
            phi=BigDecimal.valueOf(1);
        }else
        {
          phi=(now.divide(before));
          phi = phi.setScale(5, RoundingMode.HALF_UP);
          BigDecimal oldBefore = before;
          before=now;
          now=now.add(oldBefore);
        }
        System.out.println(phi);
    }
}

This is my output:

run:
1.00000
2.00000
1.50000
Exception in thread "main" java.lang.ArithmeticException: Non-terminating 
decimal expansion; no exact representable decimal result.
  at java.math.BigDecimal.divide(BigDecimal.java:1690)
  at goldenratio.GoldenRatio.main(GoldenRatio.java:30)
  • 1
    *Unrelated:* Use [`BigDecimal.ONE`](https://docs.oracle.com/javase/8/docs/api/java/math/BigDecimal.html#ONE) instead of `BigDecimal.valueOf(1)`. – Andreas Feb 23 '18 at 21:16
  • 2
    Combine [`divide(before)`](https://docs.oracle.com/javase/8/docs/api/java/math/BigDecimal.html#divide-java.math.BigDecimal-) and [`setScale(5, RoundingMode.HALF_UP)`](https://docs.oracle.com/javase/8/docs/api/java/math/BigDecimal.html#setScale-int-java.math.RoundingMode-) into [`divide(before, 5, RoundingMode.HALF_UP)`](https://docs.oracle.com/javase/8/docs/api/java/math/BigDecimal.html#divide-java.math.BigDecimal-int-java.math.RoundingMode-). That way you won't have an intermediate non-terminating result. – Andreas Feb 23 '18 at 21:18
  • You set the scale for the divsion after you actually do the division. How is the compiler supposed to know how much precision you want? – Arnav Borborah Feb 23 '18 at 21:19
  • *Unrelated:* `now`, `before`, and `phi` should be local variables, not static fields, and should be initialized to `BigDecimal.ONE`, instead of assigned value when `i==1`. – Andreas Feb 23 '18 at 21:22

1 Answers1

1

See ArithmeticException: "Non-terminating decimal expansion; no exact representable decimal result"

Basically you can pass in the rounding_mode into the divide function. See below:

import java.math.*;

public class GoldenRatio {
    static BigDecimal now;
    static BigDecimal before;
    static BigDecimal phi;

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        for (int i = 1; i <= 100; i++) {
            if (i == 1) {
                now = BigDecimal.valueOf(1);
                before = BigDecimal.valueOf(1);
                phi = BigDecimal.valueOf(1);
            } else {
                phi = (now.divide(before, 5, RoundingMode.HALF_UP));
                BigDecimal oldBefore = before;
                before = now;
                now = now.add(oldBefore);
            }
            System.out.println(phi);
        }
    }
}
Benjamin Liu
  • 313
  • 1
  • 8