• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2016 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *   http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.calculator2;
18 
19 import java.math.BigInteger;
20 import com.hp.creals.CR;
21 import com.hp.creals.UnaryCRFunction;
22 
23 /**
24  * Computable real numbers, represented so that we can get exact decidable comparisons
25  * for a number of interesting special cases, including rational computations.
26  *
27  * A real number is represented as the product of two numbers with different representations:
28  * A) A BoundedRational that can only represent a subset of the rationals, but supports
29  *    exact computable comparisons.
30  * B) A lazily evaluated "constructive real number" that provides operations to evaluate
31  *    itself to any requested number of digits.
32  * Whenever possible, we choose (B) to be one of a small set of known constants about which we
33  * know more.  For example, whenever we can, we represent rationals such that (B) is 1.
34  * This scheme allows us to do some very limited symbolic computation on numbers when both
35  * have the same (B) value, as well as in some other situations.  We try to maximize that
36  * possibility.
37  *
38  * Arithmetic operations and operations that produce finite approximations may throw unchecked
39  * exceptions produced by the underlying CR and BoundedRational packages, including
40  * CR.PrecisionOverflowException and CR.AbortedException.
41  */
42 public class UnifiedReal {
43 
44     private final BoundedRational mRatFactor;
45     private final CR mCrFactor;
46     // TODO: It would be helpful to add flags to indicate whether the result is known
47     // irrational, etc.  This sometimes happens even if mCrFactor is not one of the known ones.
48     // And exact comparisons between rationals and known irrationals are decidable.
49 
50     /**
51      * Perform some nontrivial consistency checks.
52      * @hide
53      */
54     public static boolean enableChecks = true;
55 
check(boolean b)56     private static void check(boolean b) {
57         if (!b) {
58             throw new AssertionError();
59         }
60     }
61 
UnifiedReal(BoundedRational rat, CR cr)62     private UnifiedReal(BoundedRational rat, CR cr) {
63         if (rat == null) {
64             throw new ArithmeticException("Building UnifiedReal from null");
65         }
66         // We don't normally traffic in null CRs, and hence don't test explicitly.
67         mCrFactor = cr;
68         mRatFactor = rat;
69     }
70 
UnifiedReal(CR cr)71     public UnifiedReal(CR cr) {
72         this(BoundedRational.ONE, cr);
73     }
74 
UnifiedReal(BoundedRational rat)75     public UnifiedReal(BoundedRational rat) {
76         this(rat, CR_ONE);
77     }
78 
UnifiedReal(BigInteger n)79     public UnifiedReal(BigInteger n) {
80         this(new BoundedRational(n));
81     }
82 
UnifiedReal(long n)83     public UnifiedReal(long n) {
84         this(new BoundedRational(n));
85     }
86 
valueOf(double x)87     public static UnifiedReal valueOf(double x) {
88         if (x == 0.0 || x == 1.0) {
89             return valueOf((long) x);
90         }
91         return new UnifiedReal(BoundedRational.valueOf(x));
92     }
93 
valueOf(long x)94     public static UnifiedReal valueOf(long x) {
95         if (x == 0) {
96             return UnifiedReal.ZERO;
97         } else if (x == 1) {
98             return UnifiedReal.ONE;
99         } else {
100             return new UnifiedReal(BoundedRational.valueOf(x));
101         }
102     }
103 
104     // Various helpful constants
105     private final static BigInteger BIG_24 = BigInteger.valueOf(24);
106     private final static int DEFAULT_COMPARE_TOLERANCE = -1000;
107 
108     // Well-known CR constants we try to use in the mCrFactor position:
109     private final static CR CR_ONE = CR.ONE;
110     private final static CR CR_PI = CR.PI;
111     private final static CR CR_E = CR.ONE.exp();
112     private final static CR CR_SQRT2 = CR.valueOf(2).sqrt();
113     private final static CR CR_SQRT3 = CR.valueOf(3).sqrt();
114     private final static CR CR_LN2 = CR.valueOf(2).ln();
115     private final static CR CR_LN3 = CR.valueOf(3).ln();
116     private final static CR CR_LN5 = CR.valueOf(5).ln();
117     private final static CR CR_LN6 = CR.valueOf(6).ln();
118     private final static CR CR_LN7 = CR.valueOf(7).ln();
119     private final static CR CR_LN10 = CR.valueOf(10).ln();
120 
121     // Square roots that we try to recognize.
122     // We currently recognize only a small fixed collection, since the sqrt() function needs to
123     // identify numbers of the form <SQRT[i]>*n^2, and we don't otherwise know of a good
124     // algorithm for that.
125     private final static CR sSqrts[] = {
126             null,
127             CR.ONE,
128             CR_SQRT2,
129             CR_SQRT3,
130             null,
131             CR.valueOf(5).sqrt(),
132             CR.valueOf(6).sqrt(),
133             CR.valueOf(7).sqrt(),
134             null,
135             null,
136             CR.valueOf(10).sqrt() };
137 
138     // Natural logs of small integers that we try to recognize.
139     private final static CR sLogs[] = {
140             null,
141             null,
142             CR_LN2,
143             CR_LN3,
144             null,
145             CR_LN5,
146             CR_LN6,
147             CR_LN7,
148             null,
149             null,
150             CR_LN10 };
151 
152 
153     // Some convenient UnifiedReal constants.
154     public static final UnifiedReal PI = new UnifiedReal(CR_PI);
155     public static final UnifiedReal E = new UnifiedReal(CR_E);
156     public static final UnifiedReal ZERO = new UnifiedReal(BoundedRational.ZERO);
157     public static final UnifiedReal ONE = new UnifiedReal(BoundedRational.ONE);
158     public static final UnifiedReal MINUS_ONE = new UnifiedReal(BoundedRational.MINUS_ONE);
159     public static final UnifiedReal TWO = new UnifiedReal(BoundedRational.TWO);
160     public static final UnifiedReal MINUS_TWO = new UnifiedReal(BoundedRational.MINUS_TWO);
161     public static final UnifiedReal HALF = new UnifiedReal(BoundedRational.HALF);
162     public static final UnifiedReal MINUS_HALF = new UnifiedReal(BoundedRational.MINUS_HALF);
163     public static final UnifiedReal TEN = new UnifiedReal(BoundedRational.TEN);
164     public static final UnifiedReal RADIANS_PER_DEGREE
165             = new UnifiedReal(new BoundedRational(1, 180), CR_PI);
166     private static final UnifiedReal SIX = new UnifiedReal(6);
167     private static final UnifiedReal HALF_SQRT2 = new UnifiedReal(BoundedRational.HALF, CR_SQRT2);
168     private static final UnifiedReal SQRT3 = new UnifiedReal(CR_SQRT3);
169     private static final UnifiedReal HALF_SQRT3 = new UnifiedReal(BoundedRational.HALF, CR_SQRT3);
170     private static final UnifiedReal THIRD_SQRT3 = new UnifiedReal(BoundedRational.THIRD, CR_SQRT3);
171     private static final UnifiedReal PI_OVER_2 = new UnifiedReal(BoundedRational.HALF, CR_PI);
172     private static final UnifiedReal PI_OVER_3 = new UnifiedReal(BoundedRational.THIRD, CR_PI);
173     private static final UnifiedReal PI_OVER_4 = new UnifiedReal(BoundedRational.QUARTER, CR_PI);
174     private static final UnifiedReal PI_OVER_6 = new UnifiedReal(BoundedRational.SIXTH, CR_PI);
175 
176 
177     /**
178      * Given a constructive real cr, try to determine whether cr is the square root of
179      * a small integer.  If so, return its square as a BoundedRational.  Otherwise return null.
180      * We make this determination by simple table lookup, so spurious null returns are
181      * entirely possible, or even likely.
182      */
getSquare(CR cr)183     private static BoundedRational getSquare(CR cr) {
184         for (int i = 0; i < sSqrts.length; ++i) {
185              if (sSqrts[i] == cr) {
186                 return new BoundedRational(i);
187              }
188         }
189         return null;
190     }
191 
192     /**
193      * Given a constructive real cr, try to determine whether cr is the logarithm of a small
194      * integer.  If so, return exp(cr) as a BoundedRational.  Otherwise return null.
195      * We make this determination by simple table lookup, so spurious null returns are
196      * entirely possible, or even likely.
197      */
getExp(CR cr)198     private BoundedRational getExp(CR cr) {
199         for (int i = 0; i < sLogs.length; ++i) {
200              if (sLogs[i] == cr) {
201                 return new BoundedRational(i);
202              }
203         }
204         return null;
205     }
206 
207     /**
208      * If the argument is a well-known constructive real, return its name.
209      * The name of "CR_ONE" is the empty string.
210      * No named constructive reals are rational multiples of each other.
211      * Thus two UnifiedReals with different named mCrFactors can be equal only if both
212      * mRatFactors are zero or possibly if one is CR_PI and the other is CR_E.
213      * (The latter is apparently an open problem.)
214      */
crName(CR cr)215     private static String crName(CR cr) {
216         if (cr == CR_ONE) {
217             return "";
218         }
219         if (cr == CR_PI) {
220             return "\u03C0";   // GREEK SMALL LETTER PI
221         }
222         if (cr == CR_E) {
223             return "e";
224         }
225         for (int i = 0; i < sSqrts.length; ++i) {
226             if (cr == sSqrts[i]) {
227                 return "\u221A" /* SQUARE ROOT */ + i;
228             }
229         }
230         for (int i = 0; i < sLogs.length; ++i) {
231             if (cr == sLogs[i]) {
232                 return "ln(" + i + ")";
233             }
234         }
235         return null;
236     }
237 
238     /**
239      * Would crName() return non-Null?
240      */
isNamed(CR cr)241     private static boolean isNamed(CR cr) {
242         if (cr == CR_ONE || cr == CR_PI || cr == CR_E) {
243             return true;
244         }
245         for (CR r: sSqrts) {
246             if (cr == r) {
247                 return true;
248             }
249         }
250         for (CR r: sLogs) {
251             if (cr == r) {
252                 return true;
253             }
254         }
255         return false;
256     }
257 
258     /**
259      * Is cr known to be algebraic (as opposed to transcendental)?
260      * Currently only produces meaningful results for the above known special
261      * constructive reals.
262      */
definitelyAlgebraic(CR cr)263     private static boolean definitelyAlgebraic(CR cr) {
264         return cr == CR_ONE || getSquare(cr) != null;
265     }
266 
267     /**
268      * Is this number known to be rational?
269      */
definitelyRational()270     public boolean definitelyRational() {
271         return mCrFactor == CR_ONE || mRatFactor.signum() == 0;
272     }
273 
274     /**
275      * Is this number known to be irrational?
276      * TODO: We could track the fact that something is irrational with an explicit flag, which
277      * could cover many more cases.  Whether that matters in practice is TBD.
278      */
definitelyIrrational()279     public boolean definitelyIrrational() {
280         return !definitelyRational() && isNamed(mCrFactor);
281     }
282 
283     /**
284      * Is this number known to be algebraic?
285      */
definitelyAlgebraic()286     public boolean definitelyAlgebraic() {
287         return definitelyAlgebraic(mCrFactor) || mRatFactor.signum() == 0;
288     }
289 
290     /**
291      * Is this number known to be transcendental?
292      */
definitelyTranscendental()293     public boolean definitelyTranscendental() {
294         return !definitelyAlgebraic() && isNamed(mCrFactor);
295     }
296 
297 
298     /**
299      * Is it known that the two constructive reals differ by something other than a
300      * a rational factor, i.e. is it known that two UnifiedReals
301      * with those mCrFactors will compare unequal unless both mRatFactors are zero?
302      * If this returns true, then a comparison of two UnifiedReals using those two
303      * mCrFactors cannot diverge, though we don't know of a good runtime bound.
304      */
definitelyIndependent(CR r1, CR r2)305     private static boolean definitelyIndependent(CR r1, CR r2) {
306         // The question here is whether r1 = x*r2, where x is rational, where r1 and r2
307         // are in our set of special known CRs, can have a solution.
308         // This cannot happen if one is CR_ONE and the other is not.
309         // (Since all others are irrational.)
310         // This cannot happen for two named square roots, which have no repeated factors.
311         // (To see this, square both sides of the equation and factor.  Each prime
312         // factor in the numerator and denominator occurs twice.)
313         // This cannot happen for e or pi on one side, and a square root on the other.
314         // (One is transcendental, the other is algebraic.)
315         // This cannot happen for two of our special natural logs.
316         // (Otherwise ln(m) = (a/b)ln(n) ==> m = n^(a/b) ==> m^b = n^a, which is impossible
317         // because either m or n includes a prime factor not shared by the other.)
318         // This cannot happen for a log and a square root.
319         // (The Lindemann-Weierstrass theorem tells us, among other things, that if
320         // a is algebraic, then exp(a) is transcendental.  Thus if l in our finite
321         // set of logs where algebraic, expl(l), must be transacendental.
322         // But exp(l) is an integer.  Thus the logs are transcendental.  But of course the
323         // square roots are algebraic.  Thus they can't be rational multiples.)
324         // Unfortunately, we do not know whether e/pi is rational.
325         if (r1 == r2) {
326             return false;
327         }
328         CR other;
329         if (r1 == CR_E || r1 == CR_PI) {
330             return definitelyAlgebraic(r2);
331         }
332         if (r2 == CR_E || r2 == CR_PI) {
333             return definitelyAlgebraic(r1);
334         }
335         return isNamed(r1) && isNamed(r2);
336     }
337 
338     /**
339      * Convert to String reflecting raw representation.
340      * Debug or log messages only, not pretty.
341      */
toString()342     public String toString() {
343         return mRatFactor.toString() + "*" + mCrFactor.toString();
344     }
345 
346     /**
347      * Convert to readable String.
348      * Intended for user output.  Produces exact expression when possible.
349      */
toNiceString()350     public String toNiceString() {
351         if (mCrFactor == CR_ONE || mRatFactor.signum() == 0) {
352             return mRatFactor.toNiceString();
353         }
354         String name = crName(mCrFactor);
355         if (name != null) {
356             BigInteger bi = BoundedRational.asBigInteger(mRatFactor);
357             if (bi != null) {
358                 if (bi.equals(BigInteger.ONE)) {
359                     return name;
360                 }
361                 return mRatFactor.toNiceString() + name;
362             }
363             return "(" + mRatFactor.toNiceString() + ")" + name;
364         }
365         if (mRatFactor.equals(BoundedRational.ONE)) {
366             return mCrFactor.toString();
367         }
368         return crValue().toString();
369     }
370 
371     /**
372      * Will toNiceString() produce an exact representation?
373      */
exactlyDisplayable()374     public boolean exactlyDisplayable() {
375         return crName(mCrFactor) != null;
376     }
377 
378     // Number of extra bits used in evaluation below to prefer truncation to rounding.
379     // Must be <= 30.
380     private final static int EXTRA_PREC = 10;
381 
382     /*
383      * Returns a truncated representation of the result.
384      * If exactlyTruncatable(), we round correctly towards zero. Otherwise the resulting digit
385      * string may occasionally be rounded up instead.
386      * Always includes a decimal point in the result.
387      * The result includes n digits to the right of the decimal point.
388      * @param n result precision, >= 0
389      */
toStringTruncated(int n)390     public String toStringTruncated(int n) {
391         if (mCrFactor == CR_ONE || mRatFactor == BoundedRational.ZERO) {
392             return mRatFactor.toStringTruncated(n);
393         }
394         final CR scaled = CR.valueOf(BigInteger.TEN.pow(n)).multiply(crValue());
395         boolean negative = false;
396         BigInteger intScaled;
397         if (exactlyTruncatable()) {
398             intScaled = scaled.get_appr(0);
399             if (intScaled.signum() < 0) {
400                 negative = true;
401                 intScaled = intScaled.negate();
402             }
403             if (CR.valueOf(intScaled).compareTo(scaled.abs()) > 0) {
404                 intScaled = intScaled.subtract(BigInteger.ONE);
405             }
406             check(CR.valueOf(intScaled).compareTo(scaled.abs()) < 0);
407         } else {
408             // Approximate case.  Exact comparisons are impossible.
409             intScaled = scaled.get_appr(-EXTRA_PREC);
410             if (intScaled.signum() < 0) {
411                 negative = true;
412                 intScaled = intScaled.negate();
413             }
414             intScaled = intScaled.shiftRight(EXTRA_PREC);
415         }
416         String digits = intScaled.toString();
417         int len = digits.length();
418         if (len < n + 1) {
419             digits = StringUtils.repeat('0', n + 1 - len) + digits;
420             len = n + 1;
421         }
422         return (negative ? "-" : "") + digits.substring(0, len - n) + "."
423                 + digits.substring(len - n);
424     }
425 
426     /*
427      * Can we compute correctly truncated approximations of this number?
428      */
429     public boolean exactlyTruncatable() {
430         // If the value is known rational, we can do exact comparisons.
431         // If the value is known irrational, then we can safely compare to rational approximations;
432         // equality is impossible; hence the comparison must converge.
433         // The only problem cases are the ones in which we don't know.
434         return mCrFactor == CR_ONE || mRatFactor == BoundedRational.ZERO || definitelyIrrational();
435     }
436 
437     /**
438      * Return a double approximation.
439      * Rational arguments are currently rounded to nearest, with ties away from zero.
440      * TODO: Improve rounding.
441      */
442     public double doubleValue() {
443         if (mCrFactor == CR_ONE) {
444             return mRatFactor.doubleValue(); // Hopefully correctly rounded
445         } else {
446             return crValue().doubleValue(); // Approximately correctly rounded
447         }
448     }
449 
450     public CR crValue() {
451         return mRatFactor.crValue().multiply(mCrFactor);
452     }
453 
454     /**
455      * Are this and r exactly comparable?
456      */
457     public boolean isComparable(UnifiedReal u) {
458         // We check for ONE only to speed up the common case.
459         // The use of a tolerance here means we can spuriously return false, not true.
460         return mCrFactor == u.mCrFactor
461                 && (isNamed(mCrFactor) || mCrFactor.signum(DEFAULT_COMPARE_TOLERANCE) != 0)
462                 || mRatFactor.signum() == 0 && u.mRatFactor.signum() == 0
463                 || definitelyIndependent(mCrFactor, u.mCrFactor)
464                 || crValue().compareTo(u.crValue(), DEFAULT_COMPARE_TOLERANCE) != 0;
465     }
466 
467     /**
468      * Return +1 if this is greater than r, -1 if this is less than r, or 0 of the two are
469      * known to be equal.
470      * May diverge if the two are equal and !isComparable(r).
471      */
472     public int compareTo(UnifiedReal u) {
473         if (definitelyZero() && u.definitelyZero()) return 0;
474         if (mCrFactor == u.mCrFactor) {
475             int signum = mCrFactor.signum();  // Can diverge if mCRFactor == 0.
476             return signum * mRatFactor.compareTo(u.mRatFactor);
477         }
478         return crValue().compareTo(u.crValue());  // Can also diverge.
479     }
480 
481     /**
482      * Return +1 if this is greater than r, -1 if this is less than r, or possibly 0 of the two are
483      * within 2^a of each other.
484      */
485     public int compareTo(UnifiedReal u, int a) {
486         if (isComparable(u)) {
487             return compareTo(u);
488         } else {
489             return crValue().compareTo(u.crValue(), a);
490         }
491     }
492 
493     /**
494      * Return compareTo(ZERO, a).
495      */
496     public int signum(int a) {
497         return compareTo(ZERO, a);
498     }
499 
500     /**
501      * Return compareTo(ZERO).
502      * May diverge for ZERO argument if !isComparable(ZERO).
503      */
504     public int signum() {
505         return compareTo(ZERO);
506     }
507 
508     /**
509      * Equality comparison.  May erroneously return true if values differ by less than 2^a,
510      * and !isComparable(u).
511      */
512     public boolean approxEquals(UnifiedReal u, int a) {
513         if (isComparable(u)) {
514             if (definitelyIndependent(mCrFactor, u.mCrFactor)
515                     && (mRatFactor.signum() != 0 || u.mRatFactor.signum() != 0)) {
516                 // No need to actually evaluate, though we don't know which is larger.
517                 return false;
518             } else {
519                 return compareTo(u) == 0;
520             }
521         }
522         return crValue().compareTo(u.crValue(), a) == 0;
523     }
524 
525     /**
526      * Returns true if values are definitely known to be equal, false in all other cases.
527      * This does not satisfy the contract for Object.equals().
528      */
529     public boolean definitelyEquals(UnifiedReal u) {
530         return isComparable(u) && compareTo(u) == 0;
531     }
532 
533     @Override
534     public int hashCode() {
535         // Better useless than wrong. Probably.
536         return 0;
537     }
538 
539     @Override
540     public boolean equals(Object r) {
541         if (r == null || !(r instanceof UnifiedReal)) {
542             return false;
543         }
544         // This is almost certainly a programming error. Don't even try.
545         throw new AssertionError("Can't compare UnifiedReals for exact equality");
546     }
547 
548     /**
549      * Returns true if values are definitely known not to be equal, false in all other cases.
550      * Performs no approximate evaluation.
551      */
552     public boolean definitelyNotEquals(UnifiedReal u) {
553         boolean isNamed = isNamed(mCrFactor);
554         boolean uIsNamed = isNamed(u.mCrFactor);
555         if (isNamed && uIsNamed) {
556             if (definitelyIndependent(mCrFactor, u.mCrFactor)) {
557                 return mRatFactor.signum() != 0 || u.mRatFactor.signum() != 0;
558             } else if (mCrFactor == u.mCrFactor) {
559                 return !mRatFactor.equals(u.mRatFactor);
560             }
561             return !mRatFactor.equals(u.mRatFactor);
562         }
563         if (mRatFactor.signum() == 0) {
564             return uIsNamed && u.mRatFactor.signum() != 0;
565         }
566         if (u.mRatFactor.signum() == 0) {
567             return isNamed && mRatFactor.signum() != 0;
568         }
569         return false;
570     }
571 
572     // And some slightly faster convenience functions for special cases:
573 
574     public boolean definitelyZero() {
575         return mRatFactor.signum() == 0;
576     }
577 
578     /**
579      * Can this number be determined to be definitely nonzero without performing approximate
580      * evaluation?
581      */
582     public boolean definitelyNonZero() {
583         return isNamed(mCrFactor) && mRatFactor.signum() != 0;
584     }
585 
586     public boolean definitelyOne() {
587         return mCrFactor == CR_ONE && mRatFactor.equals(BoundedRational.ONE);
588     }
589 
590     /**
591      * Return equivalent BoundedRational, if known to exist, null otherwise
592      */
593     public BoundedRational boundedRationalValue() {
594         if (mCrFactor == CR_ONE || mRatFactor.signum() == 0) {
595             return mRatFactor;
596         }
597         return null;
598     }
599 
600     /**
601      * Returns equivalent BigInteger result if it exists, null if not.
602      */
603     public BigInteger bigIntegerValue() {
604         final BoundedRational r = boundedRationalValue();
605         return BoundedRational.asBigInteger(r);
606     }
607 
608     public UnifiedReal add(UnifiedReal u) {
609         if (mCrFactor == u.mCrFactor) {
610             BoundedRational nRatFactor = BoundedRational.add(mRatFactor, u.mRatFactor);
611             if (nRatFactor != null) {
612                 return new UnifiedReal(nRatFactor, mCrFactor);
613             }
614         }
615         if (definitelyZero()) {
616             // Avoid creating new mCrFactor, even if they don't currently match.
617             return u;
618         }
619         if (u.definitelyZero()) {
620             return this;
621         }
622         return new UnifiedReal(crValue().add(u.crValue()));
623     }
624 
625     public UnifiedReal negate() {
626         return new UnifiedReal(BoundedRational.negate(mRatFactor), mCrFactor);
627     }
628 
629     public UnifiedReal subtract(UnifiedReal u) {
630         return add(u.negate());
631     }
632 
633     public UnifiedReal multiply(UnifiedReal u) {
634         // Preserve a preexisting mCrFactor when we can.
635         if (mCrFactor == CR_ONE) {
636             BoundedRational nRatFactor = BoundedRational.multiply(mRatFactor, u.mRatFactor);
637             if (nRatFactor != null) {
638                 return new UnifiedReal(nRatFactor, u.mCrFactor);
639             }
640         }
641         if (u.mCrFactor == CR_ONE) {
642             BoundedRational nRatFactor = BoundedRational.multiply(mRatFactor, u.mRatFactor);
643             if (nRatFactor != null) {
644                 return new UnifiedReal(nRatFactor, mCrFactor);
645             }
646         }
647         if (definitelyZero() || u.definitelyZero()) {
648             return ZERO;
649         }
650         if (mCrFactor == u.mCrFactor) {
651             BoundedRational square = getSquare(mCrFactor);
652             if (square != null) {
653                 BoundedRational nRatFactor = BoundedRational.multiply(
654                         BoundedRational.multiply(square, mRatFactor), u.mRatFactor);
655                 if (nRatFactor != null) {
656                     return new UnifiedReal(nRatFactor);
657                 }
658             }
659         }
660         // Probably a bit cheaper to multiply component-wise.
661         BoundedRational nRatFactor = BoundedRational.multiply(mRatFactor, u.mRatFactor);
662         if (nRatFactor != null) {
663             return new UnifiedReal(nRatFactor, mCrFactor.multiply(u.mCrFactor));
664         }
665         return new UnifiedReal(crValue().multiply(u.crValue()));
666     }
667 
668     public static class ZeroDivisionException extends ArithmeticException {
669         public ZeroDivisionException() {
670             super("Division by zero");
671         }
672     }
673 
674     /**
675      * Return the reciprocal.
676      */
677     public UnifiedReal inverse() {
678         if (definitelyZero()) {
679             throw new ZeroDivisionException();
680         }
681         BoundedRational square = getSquare(mCrFactor);
682         if (square != null) {
683             // 1/sqrt(n) = sqrt(n)/n
684             BoundedRational nRatFactor = BoundedRational.inverse(
685                     BoundedRational.multiply(mRatFactor, square));
686             if (nRatFactor != null) {
687                 return new UnifiedReal(nRatFactor, mCrFactor);
688             }
689         }
690         return new UnifiedReal(BoundedRational.inverse(mRatFactor), mCrFactor.inverse());
691     }
692 
693     public UnifiedReal divide(UnifiedReal u) {
694         if (mCrFactor == u.mCrFactor) {
695             if (u.definitelyZero()) {
696                 throw new ZeroDivisionException();
697             }
698             BoundedRational nRatFactor = BoundedRational.divide(mRatFactor, u.mRatFactor);
699             if (nRatFactor != null) {
700                 return new UnifiedReal(nRatFactor, CR_ONE);
701             }
702         }
703         return multiply(u.inverse());
704     }
705 
706     /**
707      * Return the square root.
708      * This may fail to return a known rational value, even when the result is rational.
709      */
710     public UnifiedReal sqrt() {
711         if (definitelyZero()) {
712             return ZERO;
713         }
714         if (mCrFactor == CR_ONE) {
715             BoundedRational ratSqrt;
716             // Check for all arguments of the form <perfect rational square> * small_int,
717             // where small_int has a known sqrt.  This includes the small_int = 1 case.
718             for (int divisor = 1; divisor < sSqrts.length; ++divisor) {
719                 if (sSqrts[divisor] != null) {
720                     ratSqrt = BoundedRational.sqrt(
721                             BoundedRational.divide(mRatFactor, new BoundedRational(divisor)));
722                     if (ratSqrt != null) {
723                         return new UnifiedReal(ratSqrt, sSqrts[divisor]);
724                     }
725                 }
726             }
727         }
728         return new UnifiedReal(crValue().sqrt());
729     }
730 
731     /**
732      * Return (this mod 2pi)/(pi/6) as a BigInteger, or null if that isn't easily possible.
733      */
734     private BigInteger getPiTwelfths() {
735         if (definitelyZero()) return BigInteger.ZERO;
736         if (mCrFactor == CR_PI) {
737             BigInteger quotient = BoundedRational.asBigInteger(
738                     BoundedRational.multiply(mRatFactor, BoundedRational.TWELVE));
739             if (quotient == null) {
740                 return null;
741             }
742             return quotient.mod(BIG_24);
743         }
744         return null;
745     }
746 
747     /**
748      * Computer the sin() for an integer multiple n of pi/12, if easily representable.
749      * @param n value between 0 and 23 inclusive.
750      */
751     private static UnifiedReal sinPiTwelfths(int n) {
752         if (n >= 12) {
753             UnifiedReal negResult = sinPiTwelfths(n - 12);
754             return negResult == null ? null : negResult.negate();
755         }
756         switch (n) {
757         case 0:
758             return ZERO;
759         case 2: // 30 degrees
760             return HALF;
761         case 3: // 45 degrees
762             return HALF_SQRT2;
763         case 4: // 60 degrees
764             return HALF_SQRT3;
765         case 6:
766             return ONE;
767         case 8:
768             return HALF_SQRT3;
769         case 9:
770             return HALF_SQRT2;
771         case 10:
772             return HALF;
773         default:
774             return null;
775         }
776     }
777 
778     public UnifiedReal sin() {
779         BigInteger piTwelfths = getPiTwelfths();
780         if (piTwelfths != null) {
781             UnifiedReal result = sinPiTwelfths(piTwelfths.intValue());
782             if (result != null) {
783                 return result;
784             }
785         }
786         return new UnifiedReal(crValue().sin());
787     }
788 
789     private static UnifiedReal cosPiTwelfths(int n) {
790         int sinArg = n + 6;
791         if (sinArg >= 24) {
792             sinArg -= 24;
793         }
794         return sinPiTwelfths(sinArg);
795     }
796 
797     public UnifiedReal cos() {
798         BigInteger piTwelfths = getPiTwelfths();
799         if (piTwelfths != null) {
800             UnifiedReal result = cosPiTwelfths(piTwelfths.intValue());
801             if (result != null) {
802                 return result;
803             }
804         }
805         return new UnifiedReal(crValue().cos());
806     }
807 
808     public UnifiedReal tan() {
809         BigInteger piTwelfths = getPiTwelfths();
810         if (piTwelfths != null) {
811             int i = piTwelfths.intValue();
812             if (i == 6 || i == 18) {
813                 throw new ArithmeticException("Tangent undefined");
814             }
815             UnifiedReal top = sinPiTwelfths(i);
816             UnifiedReal bottom = cosPiTwelfths(i);
817             if (top != null && bottom != null) {
818                 return top.divide(bottom);
819             }
820         }
821         return sin().divide(cos());
822     }
823 
824     // Throw an exception if the argument is definitely out of bounds for asin or acos.
825     private void checkAsinDomain() {
826         if (isComparable(ONE) && (compareTo(ONE) > 0 || compareTo(MINUS_ONE) < 0)) {
827             throw new ArithmeticException("inverse trig argument out of range");
828         }
829     }
830 
831     /**
832      * Return asin(n/2).  n is between -2 and 2.
833      */
834     public static UnifiedReal asinHalves(int n){
835         if (n < 0) {
836             return (asinHalves(-n).negate());
837         }
838         switch (n) {
839         case 0:
840             return ZERO;
841         case 1:
842             return new UnifiedReal(BoundedRational.SIXTH, CR.PI);
843         case 2:
844             return new UnifiedReal(BoundedRational.HALF, CR.PI);
845         }
846         throw new AssertionError("asinHalves: Bad argument");
847     }
848 
849     /**
850      * Return asin of this, assuming this is not an integral multiple of a half.
851      */
852     public UnifiedReal asinNonHalves()
853     {
854         if (compareTo(ZERO, -10) < 0) {
855             return negate().asinNonHalves().negate();
856         }
857         if (definitelyEquals(HALF_SQRT2)) {
858             return new UnifiedReal(BoundedRational.QUARTER, CR_PI);
859         }
860         if (definitelyEquals(HALF_SQRT3)) {
861             return new UnifiedReal(BoundedRational.THIRD, CR_PI);
862         }
863         return new UnifiedReal(crValue().asin());
864     }
865 
866     public UnifiedReal asin() {
867         checkAsinDomain();
868         final BigInteger halves = multiply(TWO).bigIntegerValue();
869         if (halves != null) {
870             return asinHalves(halves.intValue());
871         }
872         if (mCrFactor == CR.ONE || mCrFactor != CR_SQRT2 ||mCrFactor != CR_SQRT3) {
873             return asinNonHalves();
874         }
875         return new UnifiedReal(crValue().asin());
876     }
877 
878     public UnifiedReal acos() {
879         return PI_OVER_2.subtract(asin());
880     }
881 
882     public UnifiedReal atan() {
883         if (compareTo(ZERO, -10) < 0) {
884             return negate().atan().negate();
885         }
886         final BigInteger asBI = bigIntegerValue();
887         if (asBI != null && asBI.compareTo(BigInteger.ONE) <= 0) {
888             final int asInt = asBI.intValue();
889             // These seem to be all rational cases:
890             switch (asInt) {
891             case 0:
892                 return ZERO;
893             case 1:
894                 return PI_OVER_4;
895             default:
896                 throw new AssertionError("Impossible r_int");
897             }
898         }
899         if (definitelyEquals(THIRD_SQRT3)) {
900             return PI_OVER_6;
901         }
902         if (definitelyEquals(SQRT3)) {
903             return PI_OVER_3;
904         }
905         return new UnifiedReal(UnaryCRFunction.atanFunction.execute(crValue()));
906     }
907 
908     private static final BigInteger BIG_TWO = BigInteger.valueOf(2);
909 
910     // The (in abs value) integral exponent for which we attempt to use a recursive
911     // algorithm for evaluating pow(). The recursive algorithm works independent of the sign of the
912     // base, and can produce rational results. But it can become slow for very large exponents.
913     private static final BigInteger RECURSIVE_POW_LIMIT = BigInteger.valueOf(1000);
914     // The corresponding limit when we're using rational arithmetic. This should fail fast
915     // anyway, but we avoid ridiculously deep recursion.
916     private static final BigInteger HARD_RECURSIVE_POW_LIMIT = BigInteger.ONE.shiftLeft(1000);
917 
918     /**
919      * Compute an integral power of a constructive real, using the standard recursive algorithm.
920      * exp is known to be positive.
921      */
922     private static CR recursivePow(CR base, BigInteger exp) {
923         if (exp.equals(BigInteger.ONE)) {
924             return base;
925         }
926         if (exp.testBit(0)) {
927             return base.multiply(recursivePow(base, exp.subtract(BigInteger.ONE)));
928         }
929         CR tmp = recursivePow(base, exp.shiftRight(1));
930         if (Thread.interrupted()) {
931             throw new CR.AbortedException();
932         }
933         return tmp.multiply(tmp);
934     }
935 
936     /**
937      * Compute an integral power of a constructive real, using the exp function when
938      * we safely can. Use recursivePow when we can't. exp is known to be nozero.
939      */
940     private UnifiedReal expLnPow(BigInteger exp) {
941         int sign = signum(DEFAULT_COMPARE_TOLERANCE);
942         if (sign > 0) {
943             // Safe to take the log. This avoids deep recursion for huge exponents, which
944             // may actually make sense here.
945             return new UnifiedReal(crValue().ln().multiply(CR.valueOf(exp)).exp());
946         } else if (sign < 0) {
947             CR result = crValue().negate().ln().multiply(CR.valueOf(exp)).exp();
948             if (exp.testBit(0) /* odd exponent */) {
949                 result = result.negate();
950             }
951             return new UnifiedReal(result);
952         } else {
953             // Base of unknown sign with integer exponent. Use a recursive computation.
954             // (Another possible option would be to use the absolute value of the base, and then
955             // adjust the sign at the end.  But that would have to be done in the CR
956             // implementation.)
957             if (exp.signum() < 0) {
958                 // This may be very expensive if exp.negate() is large.
959                 return new UnifiedReal(recursivePow(crValue(), exp.negate()).inverse());
960             } else {
961                 return new UnifiedReal(recursivePow(crValue(), exp));
962             }
963         }
964     }
965 
966 
967     /**
968      * Compute an integral power of this.
969      * This recurses roughly as deeply as the number of bits in the exponent, and can, in
970      * ridiculous cases, result in a stack overflow.
971      */
972     private UnifiedReal pow(BigInteger exp) {
973         if (exp.equals(BigInteger.ONE)) {
974             return this;
975         }
976         if (exp.signum() == 0) {
977             // Questionable if base has undefined value or is 0.
978             // Java.lang.Math.pow() returns 1 anyway, so we do the same.
979             return ONE;
980         }
981         BigInteger absExp = exp.abs();
982         if (mCrFactor == CR_ONE && absExp.compareTo(HARD_RECURSIVE_POW_LIMIT) <= 0) {
983             final BoundedRational ratPow = mRatFactor.pow(exp);
984             // We count on this to fail, e.g. for very large exponents, when it would
985             // otherwise be too expensive.
986             if (ratPow != null) {
987                 return new UnifiedReal(ratPow);
988             }
989         }
990         if (absExp.compareTo(RECURSIVE_POW_LIMIT) > 0) {
991             return expLnPow(exp);
992         }
993         BoundedRational square = getSquare(mCrFactor);
994         if (square != null) {
995             final BoundedRational nRatFactor =
996                     BoundedRational.multiply(mRatFactor.pow(exp), square.pow(exp.shiftRight(1)));
997             if (nRatFactor != null) {
998                 if (exp.and(BigInteger.ONE).intValue() == 1) {
999                     // Odd power: Multiply by remaining square root.
1000                     return new UnifiedReal(nRatFactor, mCrFactor);
1001                 } else {
1002                     return new UnifiedReal(nRatFactor);
1003                 }
1004             }
1005         }
1006         return expLnPow(exp);
1007     }
1008 
1009     /**
1010      * Return this ^ expon.
1011      * This is really only well-defined for a positive base, particularly since
1012      * 0^x is not continuous at zero. (0^0 = 1 (as is epsilon^0), but 0^epsilon is 0.
1013      * We nonetheless try to do reasonable things at zero, when we recognize that case.
1014      */
1015     public UnifiedReal pow(UnifiedReal expon) {
1016         if (mCrFactor == CR_E) {
1017             if (mRatFactor.equals(BoundedRational.ONE)) {
1018                 return expon.exp();
1019             } else {
1020                 UnifiedReal ratPart = new UnifiedReal(mRatFactor).pow(expon);
1021                 return expon.exp().multiply(ratPart);
1022             }
1023         }
1024         final BoundedRational expAsBR = expon.boundedRationalValue();
1025         if (expAsBR != null) {
1026             BigInteger expAsBI = BoundedRational.asBigInteger(expAsBR);
1027             if (expAsBI != null) {
1028                 return pow(expAsBI);
1029             } else {
1030                 // Check for exponent that is a multiple of a half.
1031                 expAsBI = BoundedRational.asBigInteger(
1032                         BoundedRational.multiply(BoundedRational.TWO, expAsBR));
1033                 if (expAsBI != null) {
1034                     return pow(expAsBI).sqrt();
1035                 }
1036             }
1037         }
1038         // If the exponent were known zero, we would have handled it above.
1039         if (definitelyZero()) {
1040             return ZERO;
1041         }
1042         int sign = signum(DEFAULT_COMPARE_TOLERANCE);
1043         if (sign < 0) {
1044             throw new ArithmeticException("Negative base for pow() with non-integer exponent");
1045         }
1046         return new UnifiedReal(crValue().ln().multiply(expon.crValue()).exp());
1047     }
1048 
1049     /**
1050      * Raise the argument to the 16th power.
1051      */
1052     private static long pow16(int n) {
1053         if (n > 10) {
1054             throw new AssertionError("Unexpected pow16 argument");
1055         }
1056         long result = n*n;
1057         result *= result;
1058         result *= result;
1059         result *= result;
1060         return result;
1061     }
1062 
1063     /**
1064      * Return the integral log with respect to the given base if it exists, 0 otherwise.
1065      * n is presumed positive.
1066      */
1067     private static long getIntLog(BigInteger n, int base) {
1068         double nAsDouble = n.doubleValue();
1069         double approx = Math.log(nAsDouble)/Math.log(base);
1070         // A relatively quick test first.
1071         // Unfortunately, this doesn't help for values to big to fit in a Double.
1072         if (!Double.isInfinite(nAsDouble) && Math.abs(approx - Math.rint(approx)) > 1.0e-6) {
1073             return 0;
1074         }
1075         long result = 0;
1076         BigInteger remaining = n;
1077         BigInteger bigBase = BigInteger.valueOf(base);
1078         BigInteger base16th = null;  // base^16, computed lazily
1079         while (n.mod(bigBase).signum() == 0) {
1080             if (Thread.interrupted()) {
1081                 throw new CR.AbortedException();
1082             }
1083             n = n.divide(bigBase);
1084             ++result;
1085             // And try a slightly faster computation for large n:
1086             if (base16th == null) {
1087                 base16th = BigInteger.valueOf(pow16(base));
1088             }
1089             while (n.mod(base16th).signum() == 0) {
1090                 n = n.divide(base16th);
1091                 result += 16;
1092             }
1093         }
1094         if (n.equals(BigInteger.ONE)) {
1095             return result;
1096         }
1097         return 0;
1098     }
1099 
1100     public UnifiedReal ln() {
1101         if (mCrFactor == CR_E) {
1102             return new UnifiedReal(mRatFactor, CR_ONE).ln().add(ONE);
1103         }
1104         if (isComparable(ZERO)) {
1105             if (signum() <= 0) {
1106                 throw new ArithmeticException("log(non-positive)");
1107             }
1108             int compare1 = compareTo(ONE, DEFAULT_COMPARE_TOLERANCE);
1109             if (compare1 == 0) {
1110                 if (definitelyEquals(ONE)) {
1111                     return ZERO;
1112                 }
1113             } else if (compare1 < 0) {
1114                 return inverse().ln().negate();
1115             }
1116             final BigInteger bi = BoundedRational.asBigInteger(mRatFactor);
1117             if (bi != null) {
1118                 if (mCrFactor == CR_ONE) {
1119                     // Check for a power of a small integer.  We can use sLogs[] to return
1120                     // a more useful answer for those.
1121                     for (int i = 0; i < sLogs.length; ++i) {
1122                         if (sLogs[i] != null) {
1123                             long intLog = getIntLog(bi, i);
1124                             if (intLog != 0) {
1125                                 return new UnifiedReal(new BoundedRational(intLog), sLogs[i]);
1126                             }
1127                         }
1128                     }
1129                 } else {
1130                     // Check for n^k * sqrt(n), for which we can also return a more useful answer.
1131                     BoundedRational square = getSquare(mCrFactor);
1132                     if (square != null) {
1133                         int intSquare = square.intValue();
1134                         if (sLogs[intSquare] != null) {
1135                             long intLog = getIntLog(bi, intSquare);
1136                             if (intLog != 0) {
1137                                 BoundedRational nRatFactor =
1138                                         BoundedRational.add(new BoundedRational(intLog),
1139                                         BoundedRational.HALF);
1140                                 if (nRatFactor != null) {
1141                                     return new UnifiedReal(nRatFactor, sLogs[intSquare]);
1142                                 }
1143                             }
1144                         }
1145                     }
1146                 }
1147             }
1148         }
1149         return new UnifiedReal(crValue().ln());
1150     }
1151 
1152     public UnifiedReal exp() {
1153         if (definitelyEquals(ZERO)) {
1154             return ONE;
1155         }
1156         if (definitelyEquals(ONE)) {
1157             // Avoid redundant computations, and ensure we recognize all instances as equal.
1158             return E;
1159         }
1160         final BoundedRational crExp = getExp(mCrFactor);
1161         if (crExp != null) {
1162             boolean needSqrt = false;
1163             BoundedRational ratExponent = mRatFactor;
1164             BigInteger asBI = BoundedRational.asBigInteger(ratExponent);
1165             if (asBI == null) {
1166                 // check for multiple of one half.
1167                 needSqrt = true;
1168                 ratExponent = BoundedRational.multiply(ratExponent, BoundedRational.TWO);
1169             }
1170             BoundedRational nRatFactor = BoundedRational.pow(crExp, ratExponent);
1171             if (nRatFactor != null) {
1172                 UnifiedReal result = new UnifiedReal(nRatFactor);
1173                 if (needSqrt) {
1174                     result = result.sqrt();
1175                 }
1176                 return result;
1177             }
1178         }
1179         return new UnifiedReal(crValue().exp());
1180     }
1181 
1182 
1183     /**
1184      * Generalized factorial.
1185      * Compute n * (n - step) * (n - 2 * step) * etc.  This can be used to compute factorial a bit
1186      * faster, especially if BigInteger uses sub-quadratic multiplication.
1187      */
1188     private static BigInteger genFactorial(long n, long step) {
1189         if (n > 4 * step) {
1190             BigInteger prod1 = genFactorial(n, 2 * step);
1191             if (Thread.interrupted()) {
1192                 throw new CR.AbortedException();
1193             }
1194             BigInteger prod2 = genFactorial(n - step, 2 * step);
1195             if (Thread.interrupted()) {
1196                 throw new CR.AbortedException();
1197             }
1198             return prod1.multiply(prod2);
1199         } else {
1200             if (n == 0) {
1201                 return BigInteger.ONE;
1202             }
1203             BigInteger res = BigInteger.valueOf(n);
1204             for (long i = n - step; i > 1; i -= step) {
1205                 res = res.multiply(BigInteger.valueOf(i));
1206             }
1207             return res;
1208         }
1209     }
1210 
1211 
1212     /**
1213      * Factorial function.
1214      * Fails if argument is clearly not an integer.
1215      * May round to nearest integer if value is close.
1216      */
1217     public UnifiedReal fact() {
1218         BigInteger asBI = bigIntegerValue();
1219         if (asBI == null) {
1220             asBI = crValue().get_appr(0);  // Correct if it was an integer.
1221             if (!approxEquals(new UnifiedReal(asBI), DEFAULT_COMPARE_TOLERANCE)) {
1222                 throw new ArithmeticException("Non-integral factorial argument");
1223             }
1224         }
1225         if (asBI.signum() < 0) {
1226             throw new ArithmeticException("Negative factorial argument");
1227         }
1228         if (asBI.bitLength() > 20) {
1229             // Will fail.  LongValue() may not work. Punt now.
1230             throw new ArithmeticException("Factorial argument too big");
1231         }
1232         BigInteger biResult = genFactorial(asBI.longValue(), 1);
1233         BoundedRational nRatFactor = new BoundedRational(biResult);
1234         return new UnifiedReal(nRatFactor);
1235     }
1236 
1237     /**
1238      * Return the number of decimal digits to the right of the decimal point required to represent
1239      * the argument exactly.
1240      * Return Integer.MAX_VALUE if that's not possible.  Never returns a value less than zero, even
1241      * if r is a power of ten.
1242      */
1243     public int digitsRequired() {
1244         if (mCrFactor == CR_ONE || mRatFactor.signum() == 0) {
1245             return BoundedRational.digitsRequired(mRatFactor);
1246         } else {
1247             return Integer.MAX_VALUE;
1248         }
1249     }
1250 
1251     /**
1252      * Return an upper bound on the number of leading zero bits.
1253      * These are the number of 0 bits
1254      * to the right of the binary point and to the left of the most significant digit.
1255      * Return Integer.MAX_VALUE if we cannot bound it.
1256      */
1257     public int leadingBinaryZeroes() {
1258         if (isNamed(mCrFactor)) {
1259             // Only ln(2) is smaller than one, and could possibly add one zero bit.
1260             // Adding 3 gives us a somewhat sloppy upper bound.
1261             final int wholeBits = mRatFactor.wholeNumberBits();
1262             if (wholeBits == Integer.MIN_VALUE) {
1263                 return Integer.MAX_VALUE;
1264             }
1265             if (wholeBits >= 3) {
1266                 return 0;
1267             } else {
1268                 return -wholeBits + 3;
1269             }
1270         }
1271         return Integer.MAX_VALUE;
1272     }
1273 
1274     /**
1275      * Is the number of bits to the left of the decimal point greater than bound?
1276      * The result is inexact: We roughly approximate the whole number bits.
1277      */
1278     public boolean approxWholeNumberBitsGreaterThan(int bound) {
1279         if (isNamed(mCrFactor)) {
1280             return mRatFactor.wholeNumberBits() > bound;
1281         } else {
1282             return crValue().get_appr(bound - 2).bitLength() > 2;
1283         }
1284     }
1285 }
1286