0

I have been trying to round using bigdecimal in java and have been running into a java.lang.ArithmeticException error that is showing Non-terminating decimal expansion.

Can anyone explain the origins of the error as I am pretty new to java? and help me with my code?

Thanks

protected BigDecimal p;
protected BigDecimal q;
protected BigDecimal d;
protected BigDecimal det;
protected BigDecimal exp;
protected int e;

    this.p = pq.getP();
    this.q = pq.getQ();

    det = ((p.subtract(BigDecimal.ONE)).multiply(q.subtract(BigDecimal.ONE)));
    exp = new BigDecimal(String.valueOf(e));

    d = (det.divide(exp).setScale(2,BigDecimal.ROUND_HALF_UP));

The variable "d" is where i believe the error is arising.

TheLiquor
  • 71
  • 7
  • Since `e` is an `int`, `new BigDecimal(String.valueOf(e))` should be [`BigDecimal.valueOf(e)`](https://docs.oracle.com/javase/7/docs/api/java/math/BigDecimal.html#valueOf%28long%29). – Andreas Apr 06 '16 at 17:09
  • @Andreas is this simply replacing the value referenced by exp instead of creating a new reference location and taking up extra memory space? – TheLiquor Apr 06 '16 at 17:50
  • @TheLiquor The main reason, since `e` is an `int`, is that converting an `int` (or `long`) to a BigDecimal is easy and fast, but *formatting* the `int` to a String, then *parsing* that to a BigDecimal is slow and wasteful. – Andreas Apr 06 '16 at 17:54
  • @Andreas okay thanks for the tip. – TheLiquor Apr 06 '16 at 17:56
  • If you're really doing RSA than you're doin' it 'rong, very, very 'rong. – President James K. Polk Apr 06 '16 at 23:24
  • well it worked right very right @James K Polk – TheLiquor Apr 07 '16 at 00:32

1 Answers1

1

You need to set the scale when you do the divide.

d = det.divide(exp, 2, BigDecimal.ROUND_HALF_UP);

Note: using double with rounding is likely to be cleaner and less error prone.

exp = new BigDecimal(e); // does the same thing if e is an int
Peter Lawrey
  • 525,659
  • 79
  • 751
  • 1,130
  • I am using small numbers right now but am writing an RSA cipher so the primes used will be too big for the doubles capacity but thank you very much works excellent now. – TheLiquor Apr 06 '16 at 16:47
  • Did question change? `e` is defined as `int`, not `double`. As an `int`, you should use [`BigDecimal.valueOf(long)`](https://docs.oracle.com/javase/7/docs/api/java/math/BigDecimal.html#valueOf%28long%29). If it had been a `double`, then you should definitely not use `new BigDecimal(double)`, but [`BigDecimal.valueOf(double)`](https://docs.oracle.com/javase/7/docs/api/java/math/BigDecimal.html#valueOf%28double%29). So, in both cases, `BigDecimal.valueOf()` is preferred over `new BigDecimal()`. – Andreas Apr 06 '16 at 17:14
  • @TheLiquor why are you needing to use `BigDecimal` for an RSA cipher? You should only be dealing with integers. – Louis Wasserman Apr 06 '16 at 17:18
  • I thought that would be the case as well but when decrypting to capture the new exponent which the cipher text is raised to i found sometimes it isnt an integer and needs to be rounded to one.@Louis Wasserman – TheLiquor Apr 06 '16 at 17:28
  • @Andreas is it considered more syntactically correct? – TheLiquor Apr 06 '16 at 17:29
  • 1
    @TheLiquor Read javadoc of [`new BigDecimal(double)`](https://docs.oracle.com/javase/7/docs/api/java/math/BigDecimal.html#BigDecimal%28double%29) and [BigDecimal.valueOf(double)](https://docs.oracle.com/javase/7/docs/api/java/math/BigDecimal.html#valueOf%28double%29): *`BigDecimal.valueOf(double)` is generally the preferred way to convert a `double` (or `float`) into a `BigDecimal`, as the value returned is equal to that resulting from constructing a `BigDecimal` from the result of using `Double.toString(double)`* – Andreas Apr 06 '16 at 17:36
  • @Andreas passing an `int` doesn't cause precision problems. – Peter Lawrey Apr 06 '16 at 19:29
  • 1
    @PeterLawrey I know, and I haven't said otherwise. I was referring to the part of your answer that is basically saying to use `new BigDecimal()` for a `double`, and that is not the recommended/preferred way because *"the results ... can be somewhat unpredictable" (javadoc)*. Use `BigDecimal.valueOf()`. --- That happens to also be true for integer values, so common values can be optimized, e.g. `BigDecimal.valueOf(1)` would return `BigDecimal.ONE` instead of `new BigDecimal(1)`. – Andreas Apr 06 '16 at 19:53