summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHans Boehm <hboehm@google.com>2019-03-06 14:49:07 -0800
committerandroid-build-merger <android-build-merger@google.com>2019-03-06 14:49:07 -0800
commit9c56c9766dba5cea862943c2349888e6d0518c15 (patch)
tree01303165fc333abb84fdede63973619709227d93
parent0e7e66270b3f1c0c50553287e6d33a0eb716867b (diff)
parent207e36f6b3a941e4162123299023ea347287ab25 (diff)
downloadcrcalc-9c56c9766dba5cea862943c2349888e6d0518c15.tar.gz
Make gl_pi_cr exception-safe am: 3dfe34c7e0 am: b1d4a0d26b
am: 207e36f6b3 Change-Id: I35691d121a9c9a08f11b7bdc14f8049634f294ba
-rw-r--r--src/com/hp/creals/CR.java36
1 files changed, 25 insertions, 11 deletions
diff --git a/src/com/hp/creals/CR.java b/src/com/hp/creals/CR.java
index 35ab0dc..c5a1c41 100644
--- a/src/com/hp/creals/CR.java
+++ b/src/com/hp/creals/CR.java
@@ -114,6 +114,8 @@
// Fix a couple of unused variable bugs. Notably selector_sign was
// accidentally locally redeclared. (This turns out to be safe but useless.)
// hboehm@google.com 11/20/2018.
+// Fix an exception-safety issue in gl_pi_CR.approximate.
+// hboehm@google.com 3/3/2019.
package com.hp.creals;
@@ -1577,6 +1579,11 @@ class gl_pi_CR extends slow_CR {
private static CR SQRT_HALF = new sqrt_CR(ONE.shiftRight(1));
protected BigInteger approximate(int p) {
+ // Get us back into a consistent state if the last computation
+ // was interrupted after pushing onto b_prec.
+ if (b_prec.size() > b_val.size()) {
+ b_prec.remove(b_prec.size() - 1);
+ }
// Rough approximations are easy.
if (p >= 0) return scale(BigInteger.valueOf(3), -p);
// We need roughly log2(p) iterations. Each iteration should
@@ -1595,28 +1602,35 @@ class gl_pi_CR extends slow_CR {
// Current values correspond to n, next_ values to n + 1
// b_prec.size() == b_val.size() >= n + 1
final BigInteger next_a = a.add(b).shiftRight(1);
+ final BigInteger next_b;
final BigInteger a_diff = a.subtract(next_a);
- CR next_b_as_CR;
final BigInteger b_prod = a.multiply(b).shiftRight(-eval_prec);
- // We the compute square root approximations using a nested
+ // We compute square root approximations using a nested
// temporary CR computation, to avoid implementing BigInteger
// square roots separately.
final CR b_prod_as_CR = CR.valueOf(b_prod).shiftRight(-eval_prec);
if (b_prec.size() == n + 1) {
- // Need an n+1st slot.
- b_prec.add(null);
- b_val.add(null);
- next_b_as_CR = b_prod_as_CR.sqrt();
+ // Add an n+1st slot.
+ // Take care to make this exception-safe; b_prec and b_val
+ // must remain consistent, even if we are interrupted, or run
+ // out of memory. It's OK to just push on b_prec in that case.
+ final CR next_b_as_CR = b_prod_as_CR.sqrt();
+ next_b = next_b_as_CR.get_appr(eval_prec);
+ final BigInteger scaled_next_b = scale(next_b, -extra_eval_prec);
+ b_prec.add(p);
+ b_val.add(scaled_next_b);
} else {
// Reuse previous approximation to reduce sqrt iterations,
// hopefully to one.
- next_b_as_CR = new sqrt_CR(b_prod_as_CR, b_prec.get(n + 1),
- b_val.get(n + 1));
+ final CR next_b_as_CR =
+ new sqrt_CR(b_prod_as_CR,
+ b_prec.get(n + 1), b_val.get(n + 1));
+ next_b = next_b_as_CR.get_appr(eval_prec);
+ // We assume that set() doesn't throw for any reason.
+ b_prec.set(n + 1, p);
+ b_val.set(n + 1, scale(next_b, -extra_eval_prec));
}
// b_prec.size() == b_val.size() >= n + 2
- final BigInteger next_b = next_b_as_CR.get_appr(eval_prec);
- b_prec.set(n + 1, Integer.valueOf(p));
- b_val.set(n + 1, scale(next_b, -extra_eval_prec));
final BigInteger next_t =
t.subtract(a_diff.multiply(a_diff)
.shiftLeft(n + eval_prec)); // shift dist. usually neg.