Refactor arithmetic code.  More symbolic result tracking.

Bug:21957368

Add UnifiedReal class, which represents the product of a CR and a
BoundedRational.  Preferring well-known constants in the CR part
allows us to perform some symbolic-like symplifications, such as
keeping track of rational multiples of pi.  But the real motivation
for this change is to factor out the combined rational/CR logic,
so that we can reuse it for other applications.

Our limited symbolic manipulations have several immediate effects:
- Evaluator.java is cleaner.  The actual arithmetic is isaolated
  to UnifiedReal.java, BoundedRational.java, and the external CR.java.
- We can display exact symbolic representations for some irrationals.
- We are guaranteed to produce correctly truncated results for
  those values.  Switches from zeroes to 9s can no longer occur
  for those.
- We are more likely to be able to detect division by zero
  up front instead of diverging.  1/(pi - pi) is detectable.
- Factorial argument validity checks are more likely to be exact.
- We can commonly determine the leading digit of a number near zero,
  and hence quickly produce appropriate scientific notation more
  often.
- Radian trig evaluations, like sin(pi), now produce exact rational
  results.

We also remove the separate degree-based trig function implementations,
since they are no longer needed.  Degrees transalate to exact multiples
of pi, which are now tracked correctly.

The logic for producing exact results from trig functions at special
points moved from BoundedRational to UnifiedReal, and was strengthened.

BoundedRational now uses a random normalization strategy, to allow
MAX_SIZE to be increased sufficiently to get more benefits
from some of the other changes.

Break BRTest.java into UnifiedRealTest.java and BoundedRationalTest.java.
The tests are still useful, but some now only apply to UnifiedReal,
since the transcendental functions no longer exist in BoundedRationsl.

Change-Id: Ic9d5d70252d54e17043c7328f69d93ab9225223f
diff --git a/src/com/android/calculator2/KeyMaps.java b/src/com/android/calculator2/KeyMaps.java
index f99850b..896225a 100644
--- a/src/com/android/calculator2/KeyMaps.java
+++ b/src/com/android/calculator2/KeyMaps.java
@@ -463,10 +463,15 @@
             sOutputForResultChar.put('E', "E");
             sOutputForResultChar.put(' ', String.valueOf(CHAR_DIGIT_UNKNOWN));
             sOutputForResultChar.put(ELLIPSIS.charAt(0), ELLIPSIS);
+            // Translate numbers for fraction display, but not the separating slash, which appears
+            // to be universal.  We also do not translate the ln, sqrt, pi
             sOutputForResultChar.put('/', "/");
-                        // Translate numbers for fraction display, but not
-                        // the separating slash, which appears to be
-                        // universal.
+            sOutputForResultChar.put('(', "(");
+            sOutputForResultChar.put(')', ")");
+            sOutputForResultChar.put('l', "l");
+            sOutputForResultChar.put('n', "n");
+            sOutputForResultChar.put('\u221A', "\u221A"); // SQUARE ROOT
+            sOutputForResultChar.put('\u03C0', "\u03C0"); // GREEK SMALL LETTER PI
             addButtonToOutputMap('-', R.id.op_sub);
             addButtonToOutputMap('.', R.id.dec_point);
             for (int i = 0; i <= 9; ++i) {
@@ -500,6 +505,7 @@
     /**
      * Return the localization of the string s representing a numeric answer.
      * Callable only from UI thread.
+     * A trailing e is treated as the mathematical constant, not an exponent.
      */
     public static String translateResult(String s) {
         StringBuilder result = new StringBuilder();
@@ -507,13 +513,15 @@
         validateMaps();
         for (int i = 0; i < len; ++i) {
             char c = s.charAt(i);
-            String translation = sOutputForResultChar.get(c);
-            if (translation == null) {
-                // Should not get here.  Report if we do.
-                Log.v("Calculator", "Bad character:" + c);
-                result.append(String.valueOf(c));
-            } else {
-                result.append(translation);
+            if (i < len - 1 || c != 'e') {
+                String translation = sOutputForResultChar.get(c);
+                if (translation == null) {
+                    // Should not get here.  Report if we do.
+                    Log.v("Calculator", "Bad character:" + c);
+                    result.append(String.valueOf(c));
+                } else {
+                    result.append(translation);
+                }
             }
         }
         return result.toString();