diff options
author | Hans Boehm <hboehm@google.com> | 2015-06-02 22:13:43 +0000 |
---|---|---|
committer | Android (Google) Code Review <android-gerrit@google.com> | 2015-06-02 22:13:43 +0000 |
commit | 694406b52e3bafa9da4396de836e6214e3a9d799 (patch) | |
tree | f5b35ef4905d0799c0806d8f298e67446696b54a /src | |
parent | 7531cd7dadfcb9c7df658fb2193c42b65ea0e21f (diff) | |
parent | 4db31b490443e4454d98a5ae2bc44b87149accfe (diff) | |
download | android_packages_apps_ExactCalculator-694406b52e3bafa9da4396de836e6214e3a9d799.tar.gz android_packages_apps_ExactCalculator-694406b52e3bafa9da4396de836e6214e3a9d799.tar.bz2 android_packages_apps_ExactCalculator-694406b52e3bafa9da4396de836e6214e3a9d799.zip |
Merge "Implement percent and new inverse functions" into mnc-dev
Diffstat (limited to 'src')
-rw-r--r-- | src/com/android/calculator2/BoundedRational.java | 19 | ||||
-rw-r--r-- | src/com/android/calculator2/Calculator.java | 10 | ||||
-rw-r--r-- | src/com/android/calculator2/CalculatorExpr.java | 56 | ||||
-rw-r--r-- | src/com/android/calculator2/Evaluator.java | 24 | ||||
-rw-r--r-- | src/com/android/calculator2/KeyMaps.java | 7 |
5 files changed, 91 insertions, 25 deletions
diff --git a/src/com/android/calculator2/BoundedRational.java b/src/com/android/calculator2/BoundedRational.java index ee2ee92..a6dd6d9 100644 --- a/src/com/android/calculator2/BoundedRational.java +++ b/src/com/android/calculator2/BoundedRational.java @@ -229,6 +229,14 @@ public class BoundedRational { return null; } + private static BoundedRational map0to1(BoundedRational r) { + if (r == null) return null; + if (r.mNum.equals(BigInteger.ZERO)) { + return ONE; + } + return null; + } + private static BoundedRational map1to0(BoundedRational r) { if (r == null) return null; if (r.mNum.equals(r.mDen)) { @@ -345,12 +353,7 @@ public class BoundedRational { } public static BoundedRational cos(BoundedRational r) { - // Maps 0 to 1, null otherwise - if (r == null) return null; - if (r.mNum.equals(BigInteger.ZERO)) { - return ONE; - } - return null; + return map0to1(r); } public static BoundedRational degreeCos(BoundedRational r) { @@ -403,6 +406,10 @@ public class BoundedRational { return map1to0(r); } + public static BoundedRational exp(BoundedRational r) { + return map0to1(r); + } + // Return the base 10 log of n, if n is a power of 10, -1 otherwise. // n must be positive. private static long b10Log(BigInteger n) { diff --git a/src/com/android/calculator2/Calculator.java b/src/com/android/calculator2/Calculator.java index 0970174..b2cf477 100644 --- a/src/com/android/calculator2/Calculator.java +++ b/src/com/android/calculator2/Calculator.java @@ -227,12 +227,18 @@ public class Calculator extends Activity mInvertibleButtons = new View[] { findViewById(R.id.fun_sin), findViewById(R.id.fun_cos), - findViewById(R.id.fun_tan) + findViewById(R.id.fun_tan), + findViewById(R.id.fun_ln), + findViewById(R.id.fun_log), + findViewById(R.id.op_sqrt) }; mInverseButtons = new View[] { findViewById(R.id.fun_arcsin), findViewById(R.id.fun_arccos), - findViewById(R.id.fun_arctan) + findViewById(R.id.fun_arctan), + findViewById(R.id.fun_exp), + findViewById(R.id.fun_10pow), + findViewById(R.id.op_sqr) }; mEvaluator = new Evaluator(this, mResultText); diff --git a/src/com/android/calculator2/CalculatorExpr.java b/src/com/android/calculator2/CalculatorExpr.java index e5be4b9..6771b52 100644 --- a/src/com/android/calculator2/CalculatorExpr.java +++ b/src/com/android/calculator2/CalculatorExpr.java @@ -582,7 +582,7 @@ class CalculatorExpr { case R.id.const_pi: return new EvalRet(i+1, CR.PI, null); case R.id.const_e: - return new EvalRet(i+1, CR.valueOf(1).exp(), null); + return new EvalRet(i+1, REAL_E, null); case R.id.op_sqrt: // Seems to have highest precedence. // Does not add implicit paren. @@ -635,6 +635,12 @@ class CalculatorExpr { ratVal = BoundedRational.ln(argVal.mRatVal); if (ratVal != null) break; return new EvalRet(argVal.mPos, argVal.mVal.ln(), null); + case R.id.fun_exp: + argVal = evalExpr(i+1, ec); + if (isOperator(argVal.mPos, R.id.rparen, ec)) argVal.mPos++; + ratVal = BoundedRational.exp(argVal.mRatVal); + if (ratVal != null) break; + return new EvalRet(argVal.mPos, argVal.mVal.exp(), null); case R.id.fun_log: argVal = evalExpr(i+1, ec); if (isOperator(argVal.mPos, R.id.rparen, ec)) argVal.mPos++; @@ -702,35 +708,59 @@ class CalculatorExpr { // Test for integer-ness to 100 bits past binary point. private static final BigInteger MASK = BigInteger.ONE.shiftLeft(-TEST_PREC).subtract(BigInteger.ONE); + private static final CR REAL_E = CR.valueOf(1).exp(); + private static final CR REAL_ONE_HUNDREDTH = CR.valueOf(100).inverse(); + private static final BoundedRational RATIONAL_ONE_HUNDREDTH = + new BoundedRational(1,100); private static boolean isApprInt(CR x) { BigInteger appr = x.get_appr(TEST_PREC); return appr.and(MASK).signum() == 0; } - private EvalRet evalFactorial(int i, EvalContext ec) throws SyntaxException { + private EvalRet evalSuffix(int i, EvalContext ec) throws SyntaxException { EvalRet tmp = evalUnary(i, ec); int cpos = tmp.mPos; CR cval = tmp.mVal; BoundedRational ratVal = tmp.mRatVal; - while (isOperator(cpos, R.id.op_fact, ec)) { - if (ratVal == null) { - // Assume it was an integer, but we - // didn't figure it out. - // KitKat may have used the Gamma function. - if (!isApprInt(cval)) { - throw new ArithmeticException("factorial(non-integer)"); + boolean isFact; + boolean isSquared = false; + while ((isFact = isOperator(cpos, R.id.op_fact, ec)) || + (isSquared = isOperator(cpos, R.id.op_sqr, ec)) || + isOperator(cpos, R.id.op_pct, ec)) { + if (isFact) { + if (ratVal == null) { + // Assume it was an integer, but we + // didn't figure it out. + // KitKat may have used the Gamma function. + if (!isApprInt(cval)) { + throw new ArithmeticException("factorial(non-integer)"); + } + ratVal = new BoundedRational(cval.BigIntegerValue()); + } + ratVal = BoundedRational.fact(ratVal); + cval = ratVal.CRValue(); + } else if (isSquared) { + ratVal = BoundedRational.multiply(ratVal, ratVal); + if (ratVal == null) { + cval = cval.multiply(cval); + } else { + cval = ratVal.CRValue(); + } + } else /* percent */ { + ratVal = BoundedRational.multiply(ratVal, RATIONAL_ONE_HUNDREDTH); + if (ratVal == null) { + cval = cval.multiply(REAL_ONE_HUNDREDTH); + } else { + cval = ratVal.CRValue(); } - ratVal = new BoundedRational(cval.BigIntegerValue()); } - ratVal = BoundedRational.fact(ratVal); ++cpos; } - if (ratVal != null) cval = ratVal.CRValue(); return new EvalRet(cpos, cval, ratVal); } private EvalRet evalFactor(int i, EvalContext ec) throws SyntaxException { - final EvalRet result1 = evalFactorial(i, ec); + final EvalRet result1 = evalSuffix(i, ec); int cpos = result1.mPos; // current position CR cval = result1.mVal; // value so far BoundedRational ratVal = result1.mRatVal; // int value so far diff --git a/src/com/android/calculator2/Evaluator.java b/src/com/android/calculator2/Evaluator.java index 4ddaf15..9b9e830 100644 --- a/src/com/android/calculator2/Evaluator.java +++ b/src/com/android/calculator2/Evaluator.java @@ -776,10 +776,15 @@ class Evaluator { // syntax issues, and the expression is unchanged. // Return true otherwise. boolean append(int id) { - mChangedValue = (KeyMaps.digVal(id) != KeyMaps.NOT_DIGIT - || KeyMaps.isSuffix(id) - || id == R.id.const_pi || id == R.id.const_e); - return mExpr.add(id); + if (id == R.id.fun_10pow) { + add10pow(); // Handled as macro expansion. + return true; + } else { + mChangedValue = (KeyMaps.digVal(id) != KeyMaps.NOT_DIGIT + || KeyMaps.isSuffix(id) + || id == R.id.const_pi || id == R.id.const_e); + return mExpr.add(id); + } } void delete() { @@ -865,6 +870,17 @@ class Evaluator { mExpr.append(mSaved); } + // Add the power of 10 operator to the expression. This is treated + // essentially as a macro expansion. + private void add10pow() { + CalculatorExpr ten = new CalculatorExpr(); + ten.add(R.id.digit_1); + ten.add(R.id.digit_0); + mChangedValue = true; // For consistency. Reevaluation is probably not useful. + mExpr.append(ten); + mExpr.add(R.id.op_pow); + } + // Retrieve the main expression being edited. // It is the callee's reponsibility to call cancelAll to cancel // ongoing concurrent computations before modifying the result. diff --git a/src/com/android/calculator2/KeyMaps.java b/src/com/android/calculator2/KeyMaps.java index e3b84e7..5385424 100644 --- a/src/com/android/calculator2/KeyMaps.java +++ b/src/com/android/calculator2/KeyMaps.java @@ -67,6 +67,9 @@ public class KeyMaps { return context.getString(R.string.fun_ln) + context.getString(R.string.lparen); case R.id.fun_log: return context.getString(R.string.fun_log) + context.getString(R.string.lparen); + case R.id.fun_exp: + // Button label doesn't work. + return context.getString(R.string.exponential) + context.getString(R.string.lparen); case R.id.lparen: return context.getString(R.string.lparen); case R.id.rparen: @@ -79,6 +82,9 @@ public class KeyMaps { return context.getString(R.string.op_div); case R.id.op_add: return context.getString(R.string.op_add); + case R.id.op_sqr: + // Button label doesn't work. + return context.getString(R.string.squared); case R.id.op_sub: return context.getString(R.string.op_sub); case R.id.dec_point: @@ -132,6 +138,7 @@ public class KeyMaps { switch (id) { case R.id.op_fact: case R.id.op_pct: + case R.id.op_sqr: return true; default: return false; |