Loading src/com/android/calculator2/BoundedRational.java +11 −0 Original line number Original line Diff line number Diff line Loading @@ -87,6 +87,11 @@ public class BoundedRational { return CR.valueOf(mNum).divide(CR.valueOf(mDen)); return CR.valueOf(mNum).divide(CR.valueOf(mDen)); } } // Approximate number of bits to left of binary point. public int wholeNumberBits() { return mNum.bitLength() - mDen.bitLength(); } private boolean tooBig() { private boolean tooBig() { if (mDen.equals(BigInteger.ONE)) return false; if (mDen.equals(BigInteger.ONE)) return false; return (mNum.bitLength() + mDen.bitLength() > MAX_SIZE); return (mNum.bitLength() + mDen.bitLength() > MAX_SIZE); Loading Loading @@ -418,6 +423,9 @@ public class BoundedRational { // This algorithm is very naive, but we doubt it matters. // This algorithm is very naive, but we doubt it matters. long count = 0; long count = 0; while (n.mod(BigInteger.TEN).equals(BigInteger.ZERO)) { while (n.mod(BigInteger.TEN).equals(BigInteger.ZERO)) { if (Thread.interrupted()) { throw new CR.AbortedException(); } n = n.divide(BigInteger.TEN); n = n.divide(BigInteger.TEN); ++count; ++count; } } Loading Loading @@ -502,6 +510,9 @@ public class BoundedRational { if (r.mDen.equals(BigInteger.ONE)) return 0; if (r.mDen.equals(BigInteger.ONE)) return 0; r = r.reduce(); r = r.reduce(); BigInteger den = r.mDen; BigInteger den = r.mDen; if (den.bitLength() > MAX_SIZE) { return Integer.MAX_VALUE; } while (!den.testBit(0)) { while (!den.testBit(0)) { ++powers_of_two; ++powers_of_two; den = den.shiftRight(1); den = den.shiftRight(1); Loading src/com/android/calculator2/Evaluator.java +35 −14 Original line number Original line Diff line number Diff line Loading @@ -302,7 +302,7 @@ class Evaluator { .show(); .show(); } } private final long MAX_TIMEOUT = 60000; private final long MAX_TIMEOUT = 15000; // Milliseconds. // Milliseconds. // Longer is unlikely to help unless // Longer is unlikely to help unless // we get more heap space. // we get more heap space. Loading @@ -314,11 +314,12 @@ class Evaluator { // calculator is restarted. // calculator is restarted. // We'll call that a feature; others // We'll call that a feature; others // might argue it's a bug. // might argue it's a bug. private final long mQuickTimeout = 1500; private final long QUICK_TIMEOUT = 1000; // Timeout for unrequested, speculative // Timeout for unrequested, speculative // evaluations, in milliseconds. // evaluations, in milliseconds. // Could be shorter with a faster asin() private int mMaxResultBits = 120000; // Don't try to display a larger result. // implementation. private final int MAX_MAX_RESULT_BITS = 350000; // Long timeout version. private final int QUICK_MAX_RESULT_BITS = 50000; // Instant result version. private void displayTimeoutMessage() { private void displayTimeoutMessage() { final AlertDialog.Builder builder = new AlertDialog.Builder(mCalculator) final AlertDialog.Builder builder = new AlertDialog.Builder(mCalculator) Loading @@ -329,6 +330,7 @@ class Evaluator { new DialogInterface.OnClickListener() { new DialogInterface.OnClickListener() { public void onClick(DialogInterface d, int which) { public void onClick(DialogInterface d, int which) { mTimeout = MAX_TIMEOUT; mTimeout = MAX_TIMEOUT; mMaxResultBits = MAX_MAX_RESULT_BITS; } } }); }); } } Loading Loading @@ -368,8 +370,7 @@ class Evaluator { } } @Override @Override protected void onPreExecute() { protected void onPreExecute() { long timeout = mRequired ? mTimeout : mQuickTimeout; long timeout = mRequired ? mTimeout : QUICK_TIMEOUT; if (timeout != 0) { mTimeoutRunnable = new Runnable() { mTimeoutRunnable = new Runnable() { @Override @Override public void run() { public void run() { Loading @@ -378,11 +379,22 @@ class Evaluator { }; }; mTimeoutHandler.postDelayed(mTimeoutRunnable, timeout); mTimeoutHandler.postDelayed(mTimeoutRunnable, timeout); } } private boolean isTooBig(CalculatorExpr.EvalResult res) { int maxBits = mRequired ? mMaxResultBits : QUICK_MAX_RESULT_BITS; if (res.mRatVal != null) { return res.mRatVal.wholeNumberBits() > maxBits; } else { return res.mVal.get_appr(maxBits).bitLength() > 2; } } } @Override @Override protected InitialResult doInBackground(Void... nothing) { protected InitialResult doInBackground(Void... nothing) { try { try { CalculatorExpr.EvalResult res = mExpr.eval(mDm); CalculatorExpr.EvalResult res = mExpr.eval(mDm); if (isTooBig(res)) { // Avoid starting a long uninterruptible decimal conversion. return new InitialResult(R.string.timeout); } int prec = INIT_PREC; int prec = INIT_PREC; String initCache = res.mVal.toString(prec); String initCache = res.mVal.toString(prec); int msd = getMsdPos(initCache); int msd = getMsdPos(initCache); Loading Loading @@ -422,7 +434,14 @@ class Evaluator { mEvaluator = null; mEvaluator = null; mTimeoutHandler.removeCallbacks(mTimeoutRunnable); mTimeoutHandler.removeCallbacks(mTimeoutRunnable); if (result.isError()) { if (result.isError()) { if (result.mErrorResourceId == R.string.timeout) { if (mRequired) { displayTimeoutMessage(); } mCalculator.onCancelled(); } else { mCalculator.onError(result.mErrorResourceId); mCalculator.onError(result.mErrorResourceId); } return; return; } } mVal = result.mVal; mVal = result.mVal; Loading Loading @@ -453,6 +472,8 @@ class Evaluator { } } @Override @Override protected void onCancelled(InitialResult result) { protected void onCancelled(InitialResult result) { // Invoker resets mEvaluator. mTimeoutHandler.removeCallbacks(mTimeoutRunnable); if (mRequired && !mQuiet) { if (mRequired && !mQuiet) { displayCancelledMessage(); displayCancelledMessage(); } // Otherwise timeout processing displayed message. } // Otherwise timeout processing displayed message. Loading Loading
src/com/android/calculator2/BoundedRational.java +11 −0 Original line number Original line Diff line number Diff line Loading @@ -87,6 +87,11 @@ public class BoundedRational { return CR.valueOf(mNum).divide(CR.valueOf(mDen)); return CR.valueOf(mNum).divide(CR.valueOf(mDen)); } } // Approximate number of bits to left of binary point. public int wholeNumberBits() { return mNum.bitLength() - mDen.bitLength(); } private boolean tooBig() { private boolean tooBig() { if (mDen.equals(BigInteger.ONE)) return false; if (mDen.equals(BigInteger.ONE)) return false; return (mNum.bitLength() + mDen.bitLength() > MAX_SIZE); return (mNum.bitLength() + mDen.bitLength() > MAX_SIZE); Loading Loading @@ -418,6 +423,9 @@ public class BoundedRational { // This algorithm is very naive, but we doubt it matters. // This algorithm is very naive, but we doubt it matters. long count = 0; long count = 0; while (n.mod(BigInteger.TEN).equals(BigInteger.ZERO)) { while (n.mod(BigInteger.TEN).equals(BigInteger.ZERO)) { if (Thread.interrupted()) { throw new CR.AbortedException(); } n = n.divide(BigInteger.TEN); n = n.divide(BigInteger.TEN); ++count; ++count; } } Loading Loading @@ -502,6 +510,9 @@ public class BoundedRational { if (r.mDen.equals(BigInteger.ONE)) return 0; if (r.mDen.equals(BigInteger.ONE)) return 0; r = r.reduce(); r = r.reduce(); BigInteger den = r.mDen; BigInteger den = r.mDen; if (den.bitLength() > MAX_SIZE) { return Integer.MAX_VALUE; } while (!den.testBit(0)) { while (!den.testBit(0)) { ++powers_of_two; ++powers_of_two; den = den.shiftRight(1); den = den.shiftRight(1); Loading
src/com/android/calculator2/Evaluator.java +35 −14 Original line number Original line Diff line number Diff line Loading @@ -302,7 +302,7 @@ class Evaluator { .show(); .show(); } } private final long MAX_TIMEOUT = 60000; private final long MAX_TIMEOUT = 15000; // Milliseconds. // Milliseconds. // Longer is unlikely to help unless // Longer is unlikely to help unless // we get more heap space. // we get more heap space. Loading @@ -314,11 +314,12 @@ class Evaluator { // calculator is restarted. // calculator is restarted. // We'll call that a feature; others // We'll call that a feature; others // might argue it's a bug. // might argue it's a bug. private final long mQuickTimeout = 1500; private final long QUICK_TIMEOUT = 1000; // Timeout for unrequested, speculative // Timeout for unrequested, speculative // evaluations, in milliseconds. // evaluations, in milliseconds. // Could be shorter with a faster asin() private int mMaxResultBits = 120000; // Don't try to display a larger result. // implementation. private final int MAX_MAX_RESULT_BITS = 350000; // Long timeout version. private final int QUICK_MAX_RESULT_BITS = 50000; // Instant result version. private void displayTimeoutMessage() { private void displayTimeoutMessage() { final AlertDialog.Builder builder = new AlertDialog.Builder(mCalculator) final AlertDialog.Builder builder = new AlertDialog.Builder(mCalculator) Loading @@ -329,6 +330,7 @@ class Evaluator { new DialogInterface.OnClickListener() { new DialogInterface.OnClickListener() { public void onClick(DialogInterface d, int which) { public void onClick(DialogInterface d, int which) { mTimeout = MAX_TIMEOUT; mTimeout = MAX_TIMEOUT; mMaxResultBits = MAX_MAX_RESULT_BITS; } } }); }); } } Loading Loading @@ -368,8 +370,7 @@ class Evaluator { } } @Override @Override protected void onPreExecute() { protected void onPreExecute() { long timeout = mRequired ? mTimeout : mQuickTimeout; long timeout = mRequired ? mTimeout : QUICK_TIMEOUT; if (timeout != 0) { mTimeoutRunnable = new Runnable() { mTimeoutRunnable = new Runnable() { @Override @Override public void run() { public void run() { Loading @@ -378,11 +379,22 @@ class Evaluator { }; }; mTimeoutHandler.postDelayed(mTimeoutRunnable, timeout); mTimeoutHandler.postDelayed(mTimeoutRunnable, timeout); } } private boolean isTooBig(CalculatorExpr.EvalResult res) { int maxBits = mRequired ? mMaxResultBits : QUICK_MAX_RESULT_BITS; if (res.mRatVal != null) { return res.mRatVal.wholeNumberBits() > maxBits; } else { return res.mVal.get_appr(maxBits).bitLength() > 2; } } } @Override @Override protected InitialResult doInBackground(Void... nothing) { protected InitialResult doInBackground(Void... nothing) { try { try { CalculatorExpr.EvalResult res = mExpr.eval(mDm); CalculatorExpr.EvalResult res = mExpr.eval(mDm); if (isTooBig(res)) { // Avoid starting a long uninterruptible decimal conversion. return new InitialResult(R.string.timeout); } int prec = INIT_PREC; int prec = INIT_PREC; String initCache = res.mVal.toString(prec); String initCache = res.mVal.toString(prec); int msd = getMsdPos(initCache); int msd = getMsdPos(initCache); Loading Loading @@ -422,7 +434,14 @@ class Evaluator { mEvaluator = null; mEvaluator = null; mTimeoutHandler.removeCallbacks(mTimeoutRunnable); mTimeoutHandler.removeCallbacks(mTimeoutRunnable); if (result.isError()) { if (result.isError()) { if (result.mErrorResourceId == R.string.timeout) { if (mRequired) { displayTimeoutMessage(); } mCalculator.onCancelled(); } else { mCalculator.onError(result.mErrorResourceId); mCalculator.onError(result.mErrorResourceId); } return; return; } } mVal = result.mVal; mVal = result.mVal; Loading Loading @@ -453,6 +472,8 @@ class Evaluator { } } @Override @Override protected void onCancelled(InitialResult result) { protected void onCancelled(InitialResult result) { // Invoker resets mEvaluator. mTimeoutHandler.removeCallbacks(mTimeoutRunnable); if (mRequired && !mQuiet) { if (mRequired && !mQuiet) { displayCancelledMessage(); displayCancelledMessage(); } // Otherwise timeout processing displayed message. } // Otherwise timeout processing displayed message. Loading