diff options
author | Hans Boehm <hboehm@google.com> | 2019-03-06 14:23:57 -0800 |
---|---|---|
committer | android-build-merger <android-build-merger@google.com> | 2019-03-06 14:23:57 -0800 |
commit | b1d4a0d26b9d704a5898a680fa2b556fca1796a5 (patch) | |
tree | 01303165fc333abb84fdede63973619709227d93 | |
parent | d38d20e6355e576c3750771c458498097b663aee (diff) | |
parent | 3dfe34c7e0295f733449eb150745fbfdfecffb5b (diff) | |
download | crcalc-b1d4a0d26b9d704a5898a680fa2b556fca1796a5.tar.gz |
Make gl_pi_cr exception-safe
am: 3dfe34c7e0
Change-Id: Ic531a42df90f52b9bf20e0ae9f23b670f7323832
-rw-r--r-- | src/com/hp/creals/CR.java | 36 |
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. |