xref: /aosp_15_r20/external/crcalc/src/com/hp/creals/UnaryCRFunction.java (revision a164e4c8ceb68d2ed98bfa4453ac24556007d537)
1*a164e4c8SXin Li // Copyright (c) 1999, Silicon Graphics, Inc. -- ALL RIGHTS RESERVED
2*a164e4c8SXin Li //
3*a164e4c8SXin Li // Permission is granted free of charge to copy, modify, use and distribute
4*a164e4c8SXin Li // this software  provided you include the entirety of this notice in all
5*a164e4c8SXin Li // copies made.
6*a164e4c8SXin Li //
7*a164e4c8SXin Li // THIS SOFTWARE IS PROVIDED ON AN AS IS BASIS, WITHOUT WARRANTY OF ANY
8*a164e4c8SXin Li // KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, WITHOUT LIMITATION,
9*a164e4c8SXin Li // WARRANTIES THAT THE SUBJECT SOFTWARE IS FREE OF DEFECTS, MERCHANTABLE, FIT
10*a164e4c8SXin Li // FOR A PARTICULAR PURPOSE OR NON-INFRINGING.   SGI ASSUMES NO RISK AS TO THE
11*a164e4c8SXin Li // QUALITY AND PERFORMANCE OF THE SOFTWARE.   SHOULD THE SOFTWARE PROVE
12*a164e4c8SXin Li // DEFECTIVE IN ANY RESPECT, SGI ASSUMES NO COST OR LIABILITY FOR ANY
13*a164e4c8SXin Li // SERVICING, REPAIR OR CORRECTION.  THIS DISCLAIMER OF WARRANTY CONSTITUTES
14*a164e4c8SXin Li // AN ESSENTIAL PART OF THIS LICENSE. NO USE OF ANY SUBJECT SOFTWARE IS
15*a164e4c8SXin Li // AUTHORIZED HEREUNDER EXCEPT UNDER THIS DISCLAIMER.
16*a164e4c8SXin Li //
17*a164e4c8SXin Li // UNDER NO CIRCUMSTANCES AND UNDER NO LEGAL THEORY, WHETHER TORT (INCLUDING,
18*a164e4c8SXin Li // WITHOUT LIMITATION, NEGLIGENCE OR STRICT LIABILITY), CONTRACT, OR
19*a164e4c8SXin Li // OTHERWISE, SHALL SGI BE LIABLE FOR ANY DIRECT, INDIRECT, SPECIAL,
20*a164e4c8SXin Li // INCIDENTAL, OR CONSEQUENTIAL DAMAGES OF ANY CHARACTER WITH RESPECT TO THE
21*a164e4c8SXin Li // SOFTWARE INCLUDING, WITHOUT LIMITATION, DAMAGES FOR LOSS OF GOODWILL, WORK
22*a164e4c8SXin Li // STOPPAGE, LOSS OF DATA, COMPUTER FAILURE OR MALFUNCTION, OR ANY AND ALL
23*a164e4c8SXin Li // OTHER COMMERCIAL DAMAGES OR LOSSES, EVEN IF SGI SHALL HAVE BEEN INFORMED OF
24*a164e4c8SXin Li // THE POSSIBILITY OF SUCH DAMAGES.  THIS LIMITATION OF LIABILITY SHALL NOT
25*a164e4c8SXin Li // APPLY TO LIABILITY RESULTING FROM SGI's NEGLIGENCE TO THE EXTENT APPLICABLE
26*a164e4c8SXin Li // LAW PROHIBITS SUCH LIMITATION.  SOME JURISDICTIONS DO NOT ALLOW THE
27*a164e4c8SXin Li // EXCLUSION OR LIMITATION OF INCIDENTAL OR CONSEQUENTIAL DAMAGES, SO THAT
28*a164e4c8SXin Li // EXCLUSION AND LIMITATION MAY NOT APPLY TO YOU.
29*a164e4c8SXin Li //
30*a164e4c8SXin Li // These license terms shall be governed by and construed in accordance with
31*a164e4c8SXin Li // the laws of the United States and the State of California as applied to
32*a164e4c8SXin Li // agreements entered into and to be performed entirely within California
33*a164e4c8SXin Li // between California residents.  Any litigation relating to these license
34*a164e4c8SXin Li // terms shall be subject to the exclusive jurisdiction of the Federal Courts
35*a164e4c8SXin Li // of the Northern District of California (or, absent subject matter
36*a164e4c8SXin Li // jurisdiction in such courts, the courts of the State of California), with
37*a164e4c8SXin Li // venue lying exclusively in Santa Clara County, California.
38*a164e4c8SXin Li //
39*a164e4c8SXin Li // 5/2014 Added Strings to ArithmeticExceptions.
40*a164e4c8SXin Li // 5/2015 Added support for direct asin() implementation in CR.
41*a164e4c8SXin Li 
42*a164e4c8SXin Li package com.hp.creals;
43*a164e4c8SXin Li // import android.util.Log;
44*a164e4c8SXin Li 
45*a164e4c8SXin Li import java.math.BigInteger;
46*a164e4c8SXin Li 
47*a164e4c8SXin Li /**
48*a164e4c8SXin Li * Unary functions on constructive reals implemented as objects.
49*a164e4c8SXin Li * The <TT>execute</tt> member computes the function result.
50*a164e4c8SXin Li * Unary function objects on constructive reals inherit from
51*a164e4c8SXin Li * <TT>UnaryCRFunction</tt>.
52*a164e4c8SXin Li */
53*a164e4c8SXin Li // Naming vaguely follows ObjectSpace JGL convention.
54*a164e4c8SXin Li public abstract class UnaryCRFunction {
execute(CR x)55*a164e4c8SXin Li     abstract public CR execute(CR x);
56*a164e4c8SXin Li 
57*a164e4c8SXin Li /**
58*a164e4c8SXin Li * The function object corresponding to the identity function.
59*a164e4c8SXin Li */
60*a164e4c8SXin Li     public static final UnaryCRFunction identityFunction =
61*a164e4c8SXin Li         new identity_UnaryCRFunction();
62*a164e4c8SXin Li 
63*a164e4c8SXin Li /**
64*a164e4c8SXin Li * The function object corresponding to the <TT>negate</tt> method of CR.
65*a164e4c8SXin Li */
66*a164e4c8SXin Li     public static final UnaryCRFunction negateFunction =
67*a164e4c8SXin Li         new negate_UnaryCRFunction();
68*a164e4c8SXin Li 
69*a164e4c8SXin Li /**
70*a164e4c8SXin Li * The function object corresponding to the <TT>inverse</tt> method of CR.
71*a164e4c8SXin Li */
72*a164e4c8SXin Li     public static final UnaryCRFunction inverseFunction =
73*a164e4c8SXin Li         new inverse_UnaryCRFunction();
74*a164e4c8SXin Li 
75*a164e4c8SXin Li /**
76*a164e4c8SXin Li * The function object corresponding to the <TT>abs</tt> method of CR.
77*a164e4c8SXin Li */
78*a164e4c8SXin Li     public static final UnaryCRFunction absFunction =
79*a164e4c8SXin Li         new abs_UnaryCRFunction();
80*a164e4c8SXin Li 
81*a164e4c8SXin Li /**
82*a164e4c8SXin Li * The function object corresponding to the <TT>exp</tt> method of CR.
83*a164e4c8SXin Li */
84*a164e4c8SXin Li     public static final UnaryCRFunction expFunction =
85*a164e4c8SXin Li         new exp_UnaryCRFunction();
86*a164e4c8SXin Li 
87*a164e4c8SXin Li /**
88*a164e4c8SXin Li * The function object corresponding to the <TT>cos</tt> method of CR.
89*a164e4c8SXin Li */
90*a164e4c8SXin Li     public static final UnaryCRFunction cosFunction =
91*a164e4c8SXin Li         new cos_UnaryCRFunction();
92*a164e4c8SXin Li 
93*a164e4c8SXin Li /**
94*a164e4c8SXin Li * The function object corresponding to the <TT>sin</tt> method of CR.
95*a164e4c8SXin Li */
96*a164e4c8SXin Li     public static final UnaryCRFunction sinFunction =
97*a164e4c8SXin Li         new sin_UnaryCRFunction();
98*a164e4c8SXin Li 
99*a164e4c8SXin Li /**
100*a164e4c8SXin Li * The function object corresponding to the tangent function.
101*a164e4c8SXin Li */
102*a164e4c8SXin Li     public static final UnaryCRFunction tanFunction =
103*a164e4c8SXin Li         new tan_UnaryCRFunction();
104*a164e4c8SXin Li 
105*a164e4c8SXin Li /**
106*a164e4c8SXin Li * The function object corresponding to the inverse sine (arcsine) function.
107*a164e4c8SXin Li * The argument must be between -1 and 1 inclusive.  The result is between
108*a164e4c8SXin Li * -PI/2 and PI/2.
109*a164e4c8SXin Li */
110*a164e4c8SXin Li     public static final UnaryCRFunction asinFunction =
111*a164e4c8SXin Li         new asin_UnaryCRFunction();
112*a164e4c8SXin Li         // The following also works, but is slower:
113*a164e4c8SXin Li         // CR half_pi = CR.PI.divide(CR.valueOf(2));
114*a164e4c8SXin Li         // UnaryCRFunction.sinFunction.inverseMonotone(half_pi.negate(),
115*a164e4c8SXin Li         //                                             half_pi);
116*a164e4c8SXin Li 
117*a164e4c8SXin Li /**
118*a164e4c8SXin Li * The function object corresponding to the inverse cosine (arccosine) function.
119*a164e4c8SXin Li * The argument must be between -1 and 1 inclusive.  The result is between
120*a164e4c8SXin Li * 0 and PI.
121*a164e4c8SXin Li */
122*a164e4c8SXin Li     public static final UnaryCRFunction acosFunction =
123*a164e4c8SXin Li         new acos_UnaryCRFunction();
124*a164e4c8SXin Li 
125*a164e4c8SXin Li /**
126*a164e4c8SXin Li * The function object corresponding to the inverse cosine (arctangent) function.
127*a164e4c8SXin Li * The result is between -PI/2 and PI/2.
128*a164e4c8SXin Li */
129*a164e4c8SXin Li     public static final UnaryCRFunction atanFunction =
130*a164e4c8SXin Li         new atan_UnaryCRFunction();
131*a164e4c8SXin Li 
132*a164e4c8SXin Li /**
133*a164e4c8SXin Li * The function object corresponding to the <TT>ln</tt> method of CR.
134*a164e4c8SXin Li */
135*a164e4c8SXin Li     public static final UnaryCRFunction lnFunction =
136*a164e4c8SXin Li         new ln_UnaryCRFunction();
137*a164e4c8SXin Li 
138*a164e4c8SXin Li /**
139*a164e4c8SXin Li * The function object corresponding to the <TT>sqrt</tt> method of CR.
140*a164e4c8SXin Li */
141*a164e4c8SXin Li     public static final UnaryCRFunction sqrtFunction =
142*a164e4c8SXin Li         new sqrt_UnaryCRFunction();
143*a164e4c8SXin Li 
144*a164e4c8SXin Li /**
145*a164e4c8SXin Li * Compose this function with <TT>f2</tt>.
146*a164e4c8SXin Li */
compose(UnaryCRFunction f2)147*a164e4c8SXin Li     public UnaryCRFunction compose(UnaryCRFunction f2) {
148*a164e4c8SXin Li         return new compose_UnaryCRFunction(this, f2);
149*a164e4c8SXin Li     }
150*a164e4c8SXin Li 
151*a164e4c8SXin Li /**
152*a164e4c8SXin Li * Compute the inverse of this function, which must be defined
153*a164e4c8SXin Li * and strictly monotone on the interval [<TT>low</tt>, <TT>high</tt>].
154*a164e4c8SXin Li * The resulting function is defined only on the image of
155*a164e4c8SXin Li * [<TT>low</tt>, <TT>high</tt>].
156*a164e4c8SXin Li * The original function may be either increasing or decreasing.
157*a164e4c8SXin Li */
inverseMonotone(CR low, CR high)158*a164e4c8SXin Li     public UnaryCRFunction inverseMonotone(CR low, CR high) {
159*a164e4c8SXin Li         return new inverseMonotone_UnaryCRFunction(this, low, high);
160*a164e4c8SXin Li     }
161*a164e4c8SXin Li 
162*a164e4c8SXin Li /**
163*a164e4c8SXin Li * Compute the derivative of a function.
164*a164e4c8SXin Li * The function must be defined on the interval [<TT>low</tt>, <TT>high</tt>],
165*a164e4c8SXin Li * and the derivative must exist, and must be continuous and
166*a164e4c8SXin Li * monotone in the open interval [<TT>low</tt>, <TT>high</tt>].
167*a164e4c8SXin Li * The result is defined only in the open interval.
168*a164e4c8SXin Li */
monotoneDerivative(CR low, CR high)169*a164e4c8SXin Li     public UnaryCRFunction monotoneDerivative(CR low, CR high) {
170*a164e4c8SXin Li         return new monotoneDerivative_UnaryCRFunction(this, low, high);
171*a164e4c8SXin Li     }
172*a164e4c8SXin Li 
173*a164e4c8SXin Li }
174*a164e4c8SXin Li 
175*a164e4c8SXin Li // Subclasses of UnaryCRFunction for various built-in functions.
176*a164e4c8SXin Li class sin_UnaryCRFunction extends UnaryCRFunction {
execute(CR x)177*a164e4c8SXin Li     public CR execute(CR x) {
178*a164e4c8SXin Li         return x.sin();
179*a164e4c8SXin Li     }
180*a164e4c8SXin Li }
181*a164e4c8SXin Li 
182*a164e4c8SXin Li class cos_UnaryCRFunction extends UnaryCRFunction {
execute(CR x)183*a164e4c8SXin Li     public CR execute(CR x) {
184*a164e4c8SXin Li         return x.cos();
185*a164e4c8SXin Li     }
186*a164e4c8SXin Li }
187*a164e4c8SXin Li 
188*a164e4c8SXin Li class tan_UnaryCRFunction extends UnaryCRFunction {
execute(CR x)189*a164e4c8SXin Li     public CR execute(CR x) {
190*a164e4c8SXin Li         return x.sin().divide(x.cos());
191*a164e4c8SXin Li     }
192*a164e4c8SXin Li }
193*a164e4c8SXin Li 
194*a164e4c8SXin Li class asin_UnaryCRFunction extends UnaryCRFunction {
execute(CR x)195*a164e4c8SXin Li     public CR execute(CR x) {
196*a164e4c8SXin Li         return x.asin();
197*a164e4c8SXin Li     }
198*a164e4c8SXin Li }
199*a164e4c8SXin Li 
200*a164e4c8SXin Li class acos_UnaryCRFunction extends UnaryCRFunction {
execute(CR x)201*a164e4c8SXin Li     public CR execute(CR x) {
202*a164e4c8SXin Li         return x.acos();
203*a164e4c8SXin Li     }
204*a164e4c8SXin Li }
205*a164e4c8SXin Li 
206*a164e4c8SXin Li // This uses the identity (sin x)^2 = (tan x)^2/(1 + (tan x)^2)
207*a164e4c8SXin Li // Since we know the tangent of the result, we can get its sine,
208*a164e4c8SXin Li // and then use the asin function.  Note that we don't always
209*a164e4c8SXin Li // want the positive square root when computing the sine.
210*a164e4c8SXin Li class atan_UnaryCRFunction extends UnaryCRFunction {
211*a164e4c8SXin Li     CR one = CR.valueOf(1);
execute(CR x)212*a164e4c8SXin Li     public CR execute(CR x) {
213*a164e4c8SXin Li         CR x2 = x.multiply(x);
214*a164e4c8SXin Li         CR abs_sin_atan = x2.divide(one.add(x2)).sqrt();
215*a164e4c8SXin Li         CR sin_atan = x.select(abs_sin_atan.negate(), abs_sin_atan);
216*a164e4c8SXin Li         return sin_atan.asin();
217*a164e4c8SXin Li     }
218*a164e4c8SXin Li }
219*a164e4c8SXin Li 
220*a164e4c8SXin Li class exp_UnaryCRFunction extends UnaryCRFunction {
execute(CR x)221*a164e4c8SXin Li     public CR execute(CR x) {
222*a164e4c8SXin Li         return x.exp();
223*a164e4c8SXin Li     }
224*a164e4c8SXin Li }
225*a164e4c8SXin Li 
226*a164e4c8SXin Li class ln_UnaryCRFunction extends UnaryCRFunction {
execute(CR x)227*a164e4c8SXin Li     public CR execute(CR x) {
228*a164e4c8SXin Li         return x.ln();
229*a164e4c8SXin Li     }
230*a164e4c8SXin Li }
231*a164e4c8SXin Li 
232*a164e4c8SXin Li class identity_UnaryCRFunction extends UnaryCRFunction {
execute(CR x)233*a164e4c8SXin Li     public CR execute(CR x) {
234*a164e4c8SXin Li         return x;
235*a164e4c8SXin Li     }
236*a164e4c8SXin Li }
237*a164e4c8SXin Li 
238*a164e4c8SXin Li class negate_UnaryCRFunction extends UnaryCRFunction {
execute(CR x)239*a164e4c8SXin Li     public CR execute(CR x) {
240*a164e4c8SXin Li         return x.negate();
241*a164e4c8SXin Li     }
242*a164e4c8SXin Li }
243*a164e4c8SXin Li 
244*a164e4c8SXin Li class inverse_UnaryCRFunction extends UnaryCRFunction {
execute(CR x)245*a164e4c8SXin Li     public CR execute(CR x) {
246*a164e4c8SXin Li         return x.inverse();
247*a164e4c8SXin Li     }
248*a164e4c8SXin Li }
249*a164e4c8SXin Li 
250*a164e4c8SXin Li class abs_UnaryCRFunction extends UnaryCRFunction {
execute(CR x)251*a164e4c8SXin Li     public CR execute(CR x) {
252*a164e4c8SXin Li         return x.abs();
253*a164e4c8SXin Li     }
254*a164e4c8SXin Li }
255*a164e4c8SXin Li 
256*a164e4c8SXin Li class sqrt_UnaryCRFunction extends UnaryCRFunction {
execute(CR x)257*a164e4c8SXin Li     public CR execute(CR x) {
258*a164e4c8SXin Li         return x.sqrt();
259*a164e4c8SXin Li     }
260*a164e4c8SXin Li }
261*a164e4c8SXin Li 
262*a164e4c8SXin Li class compose_UnaryCRFunction extends UnaryCRFunction {
263*a164e4c8SXin Li     UnaryCRFunction f1;
264*a164e4c8SXin Li     UnaryCRFunction f2;
compose_UnaryCRFunction(UnaryCRFunction func1, UnaryCRFunction func2)265*a164e4c8SXin Li     compose_UnaryCRFunction(UnaryCRFunction func1,
266*a164e4c8SXin Li                             UnaryCRFunction func2) {
267*a164e4c8SXin Li         f1 = func1; f2 = func2;
268*a164e4c8SXin Li     }
execute(CR x)269*a164e4c8SXin Li     public CR execute(CR x) {
270*a164e4c8SXin Li         return f1.execute(f2.execute(x));
271*a164e4c8SXin Li     }
272*a164e4c8SXin Li }
273*a164e4c8SXin Li 
274*a164e4c8SXin Li class inverseMonotone_UnaryCRFunction extends UnaryCRFunction {
275*a164e4c8SXin Li   // The following variables are final, so that they
276*a164e4c8SXin Li   // can be referenced from the inner class inverseIncreasingCR.
277*a164e4c8SXin Li   // I couldn't find a way to initialize these such that the
278*a164e4c8SXin Li   // compiler accepted them as final without turning them into arrays.
279*a164e4c8SXin Li     final UnaryCRFunction f[] = new UnaryCRFunction[1];
280*a164e4c8SXin Li                                 // Monotone increasing.
281*a164e4c8SXin Li                                 // If it was monotone decreasing, we
282*a164e4c8SXin Li                                 // negate it.
283*a164e4c8SXin Li     final boolean f_negated[] = new boolean[1];
284*a164e4c8SXin Li     final CR low[] = new CR[1];
285*a164e4c8SXin Li     final CR high[] = new CR[1];
286*a164e4c8SXin Li     final CR f_low[] = new CR[1];
287*a164e4c8SXin Li     final CR f_high[] = new CR[1];
288*a164e4c8SXin Li     final int max_msd[] = new int[1];
289*a164e4c8SXin Li                         // Bound on msd of both f(high) and f(low)
290*a164e4c8SXin Li     final int max_arg_prec[] = new int[1];
291*a164e4c8SXin Li                                 // base**max_arg_prec is a small fraction
292*a164e4c8SXin Li                                 // of low - high.
293*a164e4c8SXin Li     final int deriv_msd[] = new int[1];
294*a164e4c8SXin Li                                 // Rough approx. of msd of first
295*a164e4c8SXin Li                                 // derivative.
296*a164e4c8SXin Li     final static BigInteger BIG1023 = BigInteger.valueOf(1023);
297*a164e4c8SXin Li     static final boolean ENABLE_TRACE = false;  // Change to generate trace
trace(String s)298*a164e4c8SXin Li     static void trace(String s) {
299*a164e4c8SXin Li         if (ENABLE_TRACE) {
300*a164e4c8SXin Li             System.out.println(s);
301*a164e4c8SXin Li             // Change to Log.v("UnaryCRFunction", s); for Android use.
302*a164e4c8SXin Li         }
303*a164e4c8SXin Li     }
inverseMonotone_UnaryCRFunction(UnaryCRFunction func, CR l, CR h)304*a164e4c8SXin Li     inverseMonotone_UnaryCRFunction(UnaryCRFunction func, CR l, CR h) {
305*a164e4c8SXin Li         low[0] = l; high[0] = h;
306*a164e4c8SXin Li         CR tmp_f_low = func.execute(l);
307*a164e4c8SXin Li         CR tmp_f_high = func.execute(h);
308*a164e4c8SXin Li         // Since func is monotone and low < high, the following test
309*a164e4c8SXin Li         // converges.
310*a164e4c8SXin Li         if (tmp_f_low.compareTo(tmp_f_high) > 0) {
311*a164e4c8SXin Li             f[0] = UnaryCRFunction.negateFunction.compose(func);
312*a164e4c8SXin Li             f_negated[0] = true;
313*a164e4c8SXin Li             f_low[0] = tmp_f_low.negate();
314*a164e4c8SXin Li             f_high[0] = tmp_f_high.negate();
315*a164e4c8SXin Li         } else {
316*a164e4c8SXin Li             f[0] = func;
317*a164e4c8SXin Li             f_negated[0] = false;
318*a164e4c8SXin Li             f_low[0] = tmp_f_low;
319*a164e4c8SXin Li             f_high[0] = tmp_f_high;
320*a164e4c8SXin Li         }
321*a164e4c8SXin Li         max_msd[0] = low[0].abs().max(high[0].abs()).msd();
322*a164e4c8SXin Li         max_arg_prec[0] = high[0].subtract(low[0]).msd() - 4;
323*a164e4c8SXin Li         deriv_msd[0] = f_high[0].subtract(f_low[0])
324*a164e4c8SXin Li                     .divide(high[0].subtract(low[0])).msd();
325*a164e4c8SXin Li     }
326*a164e4c8SXin Li     class inverseIncreasingCR extends CR {
327*a164e4c8SXin Li         final CR arg;
inverseIncreasingCR(CR x)328*a164e4c8SXin Li         inverseIncreasingCR(CR x) {
329*a164e4c8SXin Li             arg = f_negated[0]? x.negate() : x;
330*a164e4c8SXin Li         }
331*a164e4c8SXin Li         // Comparison with a difference of one treated as equality.
sloppy_compare(BigInteger x, BigInteger y)332*a164e4c8SXin Li         int sloppy_compare(BigInteger x, BigInteger y) {
333*a164e4c8SXin Li             BigInteger difference = x.subtract(y);
334*a164e4c8SXin Li             if (difference.compareTo(big1) > 0) {
335*a164e4c8SXin Li                 return 1;
336*a164e4c8SXin Li             }
337*a164e4c8SXin Li             if (difference.compareTo(bigm1) < 0) {
338*a164e4c8SXin Li                 return -1;
339*a164e4c8SXin Li             }
340*a164e4c8SXin Li             return 0;
341*a164e4c8SXin Li         }
approximate(int p)342*a164e4c8SXin Li         protected BigInteger approximate(int p) {
343*a164e4c8SXin Li             final int extra_arg_prec = 4;
344*a164e4c8SXin Li             final UnaryCRFunction fn = f[0];
345*a164e4c8SXin Li             int small_step_deficit = 0; // Number of ineffective steps not
346*a164e4c8SXin Li                                         // yet compensated for by a binary
347*a164e4c8SXin Li                                         // search step.
348*a164e4c8SXin Li             int digits_needed = max_msd[0] - p;
349*a164e4c8SXin Li             if (digits_needed < 0) return big0;
350*a164e4c8SXin Li             int working_arg_prec = p - extra_arg_prec;
351*a164e4c8SXin Li             if (working_arg_prec > max_arg_prec[0]) {
352*a164e4c8SXin Li                 working_arg_prec = max_arg_prec[0];
353*a164e4c8SXin Li             }
354*a164e4c8SXin Li             int working_eval_prec = working_arg_prec + deriv_msd[0] - 20;
355*a164e4c8SXin Li                         // initial guess
356*a164e4c8SXin Li             // We use a combination of binary search and something like
357*a164e4c8SXin Li             // the secant method.  This always converges linearly,
358*a164e4c8SXin Li             // and should converge quadratically under favorable assumptions.
359*a164e4c8SXin Li             // F_l and f_h are always the approximate images of l and h.
360*a164e4c8SXin Li             // At any point, arg is between f_l and f_h, or no more than
361*a164e4c8SXin Li             // one outside [f_l, f_h].
362*a164e4c8SXin Li             // L and h are implicitly scaled by working_arg_prec.
363*a164e4c8SXin Li             // The scaled values of l and h are strictly between low and high.
364*a164e4c8SXin Li             // If at_left is true, then l is logically at the left
365*a164e4c8SXin Li             // end of the interval.  We approximate this by setting l to
366*a164e4c8SXin Li             // a point slightly inside the interval, and letting f_l
367*a164e4c8SXin Li             // approximate the function value at the endpoint.
368*a164e4c8SXin Li             // If at_right is true, r and f_r are set correspondingly.
369*a164e4c8SXin Li             // At the endpoints of the interval, f_l and f_h may correspond
370*a164e4c8SXin Li             // to the endpoints, even if l and h are slightly inside.
371*a164e4c8SXin Li             // F_l and f_u are scaled by working_eval_prec.
372*a164e4c8SXin Li             // Working_eval_prec may need to be adjusted depending
373*a164e4c8SXin Li             // on the derivative of f.
374*a164e4c8SXin Li             boolean at_left, at_right;
375*a164e4c8SXin Li             BigInteger l, f_l;
376*a164e4c8SXin Li             BigInteger h, f_h;
377*a164e4c8SXin Li             BigInteger low_appr = low[0].get_appr(working_arg_prec)
378*a164e4c8SXin Li                                         .add(big1);
379*a164e4c8SXin Li             BigInteger high_appr = high[0].get_appr(working_arg_prec)
380*a164e4c8SXin Li                                           .subtract(big1);
381*a164e4c8SXin Li             BigInteger arg_appr = arg.get_appr(working_eval_prec);
382*a164e4c8SXin Li             boolean have_good_appr = (appr_valid && min_prec < max_msd[0]);
383*a164e4c8SXin Li             if (digits_needed < 30 && !have_good_appr) {
384*a164e4c8SXin Li                 trace("Setting interval to entire domain");
385*a164e4c8SXin Li                 h = high_appr;
386*a164e4c8SXin Li                 f_h = f_high[0].get_appr(working_eval_prec);
387*a164e4c8SXin Li                 l = low_appr;
388*a164e4c8SXin Li                 f_l = f_low[0].get_appr(working_eval_prec);
389*a164e4c8SXin Li                 // Check for clear out-of-bounds case.
390*a164e4c8SXin Li                 // Close cases may fail in other ways.
391*a164e4c8SXin Li                   if (f_h.compareTo(arg_appr.subtract(big1)) < 0
392*a164e4c8SXin Li                     || f_l.compareTo(arg_appr.add(big1)) > 0) {
393*a164e4c8SXin Li                     throw new ArithmeticException("inverse(out-of-bounds)");
394*a164e4c8SXin Li                   }
395*a164e4c8SXin Li                 at_left = true;
396*a164e4c8SXin Li                 at_right = true;
397*a164e4c8SXin Li                 small_step_deficit = 2;        // Start with bin search steps.
398*a164e4c8SXin Li             } else {
399*a164e4c8SXin Li                 int rough_prec = p + digits_needed/2;
400*a164e4c8SXin Li 
401*a164e4c8SXin Li                 if (have_good_appr &&
402*a164e4c8SXin Li                     (digits_needed < 30 || min_prec < p + 3*digits_needed/4)) {
403*a164e4c8SXin Li                     rough_prec = min_prec;
404*a164e4c8SXin Li                 }
405*a164e4c8SXin Li                 BigInteger rough_appr = get_appr(rough_prec);
406*a164e4c8SXin Li                 trace("Setting interval based on prev. appr");
407*a164e4c8SXin Li                 trace("prev. prec = " + rough_prec + " appr = " + rough_appr);
408*a164e4c8SXin Li                 h = rough_appr.add(big1)
409*a164e4c8SXin Li                               .shiftLeft(rough_prec - working_arg_prec);
410*a164e4c8SXin Li                 l = rough_appr.subtract(big1)
411*a164e4c8SXin Li                               .shiftLeft(rough_prec - working_arg_prec);
412*a164e4c8SXin Li                 if (h.compareTo(high_appr) > 0)  {
413*a164e4c8SXin Li                     h = high_appr;
414*a164e4c8SXin Li                     f_h = f_high[0].get_appr(working_eval_prec);
415*a164e4c8SXin Li                     at_right = true;
416*a164e4c8SXin Li                 } else {
417*a164e4c8SXin Li                     CR h_cr = CR.valueOf(h).shiftLeft(working_arg_prec);
418*a164e4c8SXin Li                     f_h = fn.execute(h_cr).get_appr(working_eval_prec);
419*a164e4c8SXin Li                     at_right = false;
420*a164e4c8SXin Li                 }
421*a164e4c8SXin Li                 if (l.compareTo(low_appr) < 0) {
422*a164e4c8SXin Li                     l = low_appr;
423*a164e4c8SXin Li                     f_l = f_low[0].get_appr(working_eval_prec);
424*a164e4c8SXin Li                     at_left = true;
425*a164e4c8SXin Li                 } else {
426*a164e4c8SXin Li                     CR l_cr = CR.valueOf(l).shiftLeft(working_arg_prec);
427*a164e4c8SXin Li                     f_l = fn.execute(l_cr).get_appr(working_eval_prec);
428*a164e4c8SXin Li                     at_left = false;
429*a164e4c8SXin Li                 }
430*a164e4c8SXin Li             }
431*a164e4c8SXin Li             BigInteger difference = h.subtract(l);
432*a164e4c8SXin Li             for(int i = 0;; ++i) {
433*a164e4c8SXin Li                 if (Thread.interrupted() || please_stop)
434*a164e4c8SXin Li                     throw new AbortedException();
435*a164e4c8SXin Li                 trace("***Iteration: " + i);
436*a164e4c8SXin Li                 trace("Arg prec = " + working_arg_prec
437*a164e4c8SXin Li                       + " eval prec = " + working_eval_prec
438*a164e4c8SXin Li                       + " arg appr. = " + arg_appr);
439*a164e4c8SXin Li                 trace("l = " + l); trace("h = " + h);
440*a164e4c8SXin Li                 trace("f(l) = " + f_l); trace("f(h) = " + f_h);
441*a164e4c8SXin Li                 if (difference.compareTo(big6) < 0) {
442*a164e4c8SXin Li                     // Answer is less than 1/2 ulp away from h.
443*a164e4c8SXin Li                     return scale(h, -extra_arg_prec);
444*a164e4c8SXin Li                 }
445*a164e4c8SXin Li                 BigInteger f_difference = f_h.subtract(f_l);
446*a164e4c8SXin Li                 // Narrow the interval by dividing at a cleverly
447*a164e4c8SXin Li                 // chosen point (guess) in the middle.
448*a164e4c8SXin Li                 {
449*a164e4c8SXin Li                     BigInteger guess;
450*a164e4c8SXin Li                     boolean binary_step =
451*a164e4c8SXin Li                         (small_step_deficit > 0 || f_difference.signum() == 0);
452*a164e4c8SXin Li                     if (binary_step) {
453*a164e4c8SXin Li                         // Do a binary search step to guarantee linear
454*a164e4c8SXin Li                         // convergence.
455*a164e4c8SXin Li                         trace("binary step");
456*a164e4c8SXin Li                         guess = l.add(h).shiftRight(1);
457*a164e4c8SXin Li                         --small_step_deficit;
458*a164e4c8SXin Li                     } else {
459*a164e4c8SXin Li                       // interpolate.
460*a164e4c8SXin Li                       // f_difference is nonzero here.
461*a164e4c8SXin Li                       trace("interpolating");
462*a164e4c8SXin Li                       BigInteger arg_difference = arg_appr.subtract(f_l);
463*a164e4c8SXin Li                       BigInteger t = arg_difference.multiply(difference);
464*a164e4c8SXin Li                       BigInteger adj = t.divide(f_difference);
465*a164e4c8SXin Li                           // tentative adjustment to l to compute guess
466*a164e4c8SXin Li                       // If we are within 1/1024 of either end, back off.
467*a164e4c8SXin Li                       // This greatly improves the odds of bounding
468*a164e4c8SXin Li                       // the answer within the smaller interval.
469*a164e4c8SXin Li                       // Note that interpolation will often get us
470*a164e4c8SXin Li                       // MUCH closer than this.
471*a164e4c8SXin Li                       if (adj.compareTo(difference.shiftRight(10)) < 0) {
472*a164e4c8SXin Li                         adj = adj.shiftLeft(8);
473*a164e4c8SXin Li                         trace("adjusting left");
474*a164e4c8SXin Li                       } else if (adj.compareTo(difference.multiply(BIG1023)
475*a164e4c8SXin Li                                                        .shiftRight(10)) > 0){
476*a164e4c8SXin Li                         adj = difference.subtract(difference.subtract(adj)
477*a164e4c8SXin Li                                                   .shiftLeft(8));
478*a164e4c8SXin Li                         trace("adjusting right");
479*a164e4c8SXin Li                       }
480*a164e4c8SXin Li                       if (adj.signum() <= 0)
481*a164e4c8SXin Li                           adj = big2;
482*a164e4c8SXin Li                       if (adj.compareTo(difference) >= 0)
483*a164e4c8SXin Li                           adj = difference.subtract(big2);
484*a164e4c8SXin Li                       guess = (adj.signum() <= 0? l.add(big2) : l.add(adj));
485*a164e4c8SXin Li                     }
486*a164e4c8SXin Li                     int outcome;
487*a164e4c8SXin Li                     BigInteger tweak = big2;
488*a164e4c8SXin Li                     BigInteger f_guess;
489*a164e4c8SXin Li                     for(boolean adj_prec = false;; adj_prec = !adj_prec) {
490*a164e4c8SXin Li                         CR guess_cr = CR.valueOf(guess)
491*a164e4c8SXin Li                                         .shiftLeft(working_arg_prec);
492*a164e4c8SXin Li                         trace("Evaluating at " + guess_cr
493*a164e4c8SXin Li                               + " with precision " + working_eval_prec);
494*a164e4c8SXin Li                         CR f_guess_cr = fn.execute(guess_cr);
495*a164e4c8SXin Li                         trace("fn value = " + f_guess_cr);
496*a164e4c8SXin Li                         f_guess = f_guess_cr.get_appr(working_eval_prec);
497*a164e4c8SXin Li                         outcome = sloppy_compare(f_guess, arg_appr);
498*a164e4c8SXin Li                         if (outcome != 0) break;
499*a164e4c8SXin Li                         // Alternately increase evaluation precision
500*a164e4c8SXin Li                         // and adjust guess slightly.
501*a164e4c8SXin Li                         // This should be an unlikely case.
502*a164e4c8SXin Li                         if (adj_prec) {
503*a164e4c8SXin Li                             // adjust working_eval_prec to get enough
504*a164e4c8SXin Li                             // resolution.
505*a164e4c8SXin Li                             int adjustment = -f_guess.bitLength()/4;
506*a164e4c8SXin Li                             if (adjustment > -20) adjustment = - 20;
507*a164e4c8SXin Li                             CR l_cr = CR.valueOf(l)
508*a164e4c8SXin Li                                         .shiftLeft(working_arg_prec);
509*a164e4c8SXin Li                             CR h_cr = CR.valueOf(h)
510*a164e4c8SXin Li                                         .shiftLeft(working_arg_prec);
511*a164e4c8SXin Li                             working_eval_prec += adjustment;
512*a164e4c8SXin Li                             trace("New eval prec = " + working_eval_prec
513*a164e4c8SXin Li                                   + (at_left? "(at left)" : "")
514*a164e4c8SXin Li                                   + (at_right? "(at right)" : ""));
515*a164e4c8SXin Li                             if (at_left) {
516*a164e4c8SXin Li                                 f_l = f_low[0].get_appr(working_eval_prec);
517*a164e4c8SXin Li                             } else {
518*a164e4c8SXin Li                                 f_l = fn.execute(l_cr)
519*a164e4c8SXin Li                                         .get_appr(working_eval_prec);
520*a164e4c8SXin Li                             }
521*a164e4c8SXin Li                             if (at_right) {
522*a164e4c8SXin Li                                 f_h = f_high[0].get_appr(working_eval_prec);
523*a164e4c8SXin Li                             } else {
524*a164e4c8SXin Li                                 f_h = fn.execute(h_cr)
525*a164e4c8SXin Li                                         .get_appr(working_eval_prec);
526*a164e4c8SXin Li                             }
527*a164e4c8SXin Li                             arg_appr = arg.get_appr(working_eval_prec);
528*a164e4c8SXin Li                         } else {
529*a164e4c8SXin Li                             // guess might be exactly right; tweak it
530*a164e4c8SXin Li                             // slightly.
531*a164e4c8SXin Li                             trace("tweaking guess");
532*a164e4c8SXin Li                             BigInteger new_guess = guess.add(tweak);
533*a164e4c8SXin Li                             if (new_guess.compareTo(h) >= 0) {
534*a164e4c8SXin Li                                 guess = guess.subtract(tweak);
535*a164e4c8SXin Li                             } else {
536*a164e4c8SXin Li                                 guess = new_guess;
537*a164e4c8SXin Li                             }
538*a164e4c8SXin Li                             // If we keep hitting the right answer, it's
539*a164e4c8SXin Li                             // important to alternate which side we move it
540*a164e4c8SXin Li                             // to, so that the interval shrinks rapidly.
541*a164e4c8SXin Li                             tweak = tweak.negate();
542*a164e4c8SXin Li                         }
543*a164e4c8SXin Li                     }
544*a164e4c8SXin Li                     if (outcome > 0) {
545*a164e4c8SXin Li                         h = guess;
546*a164e4c8SXin Li                         f_h = f_guess;
547*a164e4c8SXin Li                         at_right = false;
548*a164e4c8SXin Li                     } else {
549*a164e4c8SXin Li                         l = guess;
550*a164e4c8SXin Li                         f_l = f_guess;
551*a164e4c8SXin Li                         at_left = false;
552*a164e4c8SXin Li                     }
553*a164e4c8SXin Li                     BigInteger new_difference = h.subtract(l);
554*a164e4c8SXin Li                     if (!binary_step) {
555*a164e4c8SXin Li                         if (new_difference.compareTo(difference
556*a164e4c8SXin Li                                                      .shiftRight(1)) >= 0) {
557*a164e4c8SXin Li                             ++small_step_deficit;
558*a164e4c8SXin Li                         } else {
559*a164e4c8SXin Li                             --small_step_deficit;
560*a164e4c8SXin Li                         }
561*a164e4c8SXin Li                     }
562*a164e4c8SXin Li                     difference = new_difference;
563*a164e4c8SXin Li                 }
564*a164e4c8SXin Li             }
565*a164e4c8SXin Li         }
566*a164e4c8SXin Li     }
execute(CR x)567*a164e4c8SXin Li     public CR execute(CR x) {
568*a164e4c8SXin Li         return new inverseIncreasingCR(x);
569*a164e4c8SXin Li     }
570*a164e4c8SXin Li }
571*a164e4c8SXin Li 
572*a164e4c8SXin Li class monotoneDerivative_UnaryCRFunction extends UnaryCRFunction {
573*a164e4c8SXin Li   // The following variables are final, so that they
574*a164e4c8SXin Li   // can be referenced from the inner class inverseIncreasingCR.
575*a164e4c8SXin Li     final UnaryCRFunction f[] = new UnaryCRFunction[1];
576*a164e4c8SXin Li                                 // Monotone increasing.
577*a164e4c8SXin Li                                 // If it was monotone decreasing, we
578*a164e4c8SXin Li                                 // negate it.
579*a164e4c8SXin Li     final CR low[] = new CR[1]; // endpoints and mispoint of interval
580*a164e4c8SXin Li     final CR mid[] = new CR[1];
581*a164e4c8SXin Li     final CR high[] = new CR[1];
582*a164e4c8SXin Li     final CR f_low[] = new CR[1]; // Corresponding function values.
583*a164e4c8SXin Li     final CR f_mid[] = new CR[1];
584*a164e4c8SXin Li     final CR f_high[] = new CR[1];
585*a164e4c8SXin Li     final int difference_msd[] = new int[1];  // msd of interval len.
586*a164e4c8SXin Li     final int deriv2_msd[] = new int[1];
587*a164e4c8SXin Li                                 // Rough approx. of msd of second
588*a164e4c8SXin Li                                 // derivative.
589*a164e4c8SXin Li                                 // This is increased to be an appr. bound
590*a164e4c8SXin Li                                 // on the msd of |(f'(y)-f'(x))/(x-y)|
591*a164e4c8SXin Li                                 // for any pair of points x and y
592*a164e4c8SXin Li                                 // we have considered.
593*a164e4c8SXin Li                                 // It may be better to keep a copy per
594*a164e4c8SXin Li                                 // derivative value.
595*a164e4c8SXin Li 
monotoneDerivative_UnaryCRFunction(UnaryCRFunction func, CR l, CR h)596*a164e4c8SXin Li     monotoneDerivative_UnaryCRFunction(UnaryCRFunction func, CR l, CR h) {
597*a164e4c8SXin Li         f[0] = func;
598*a164e4c8SXin Li         low[0] = l; high[0] = h;
599*a164e4c8SXin Li         mid[0] = l.add(h).shiftRight(1);
600*a164e4c8SXin Li         f_low[0] = func.execute(l);
601*a164e4c8SXin Li         f_mid[0] = func.execute(mid[0]);
602*a164e4c8SXin Li         f_high[0] = func.execute(h);
603*a164e4c8SXin Li         CR difference = h.subtract(l);
604*a164e4c8SXin Li         // compute approximate msd of
605*a164e4c8SXin Li         // ((f_high - f_mid) - (f_mid - f_low))/(high - low)
606*a164e4c8SXin Li         // This should be a very rough appr to the second derivative.
607*a164e4c8SXin Li         // We add a little slop to err on the high side, since
608*a164e4c8SXin Li         // a low estimate will cause extra iterations.
609*a164e4c8SXin Li         CR appr_diff2 = f_high[0].subtract(f_mid[0].shiftLeft(1)).add(f_low[0]);
610*a164e4c8SXin Li         difference_msd[0] = difference.msd();
611*a164e4c8SXin Li         deriv2_msd[0] = appr_diff2.msd() - difference_msd[0] + 4;
612*a164e4c8SXin Li     }
613*a164e4c8SXin Li     class monotoneDerivativeCR extends CR {
614*a164e4c8SXin Li         CR arg;
615*a164e4c8SXin Li         CR f_arg;
616*a164e4c8SXin Li         int max_delta_msd;
monotoneDerivativeCR(CR x)617*a164e4c8SXin Li         monotoneDerivativeCR(CR x) {
618*a164e4c8SXin Li             arg = x;
619*a164e4c8SXin Li             f_arg = f[0].execute(x);
620*a164e4c8SXin Li             // The following must converge, since arg must be in the
621*a164e4c8SXin Li             // open interval.
622*a164e4c8SXin Li             CR left_diff = arg.subtract(low[0]);
623*a164e4c8SXin Li             int max_delta_left_msd = left_diff.msd();
624*a164e4c8SXin Li             CR right_diff = high[0].subtract(arg);
625*a164e4c8SXin Li             int max_delta_right_msd = right_diff.msd();
626*a164e4c8SXin Li             if (left_diff.signum() < 0 || right_diff.signum() < 0) {
627*a164e4c8SXin Li                 throw new ArithmeticException("fn not monotone");
628*a164e4c8SXin Li             }
629*a164e4c8SXin Li             max_delta_msd = (max_delta_left_msd < max_delta_right_msd?
630*a164e4c8SXin Li                                 max_delta_left_msd
631*a164e4c8SXin Li                                 : max_delta_right_msd);
632*a164e4c8SXin Li         }
approximate(int p)633*a164e4c8SXin Li         protected BigInteger approximate(int p) {
634*a164e4c8SXin Li             final int extra_prec = 4;
635*a164e4c8SXin Li             int log_delta = p - deriv2_msd[0];
636*a164e4c8SXin Li             // Ensure that we stay within the interval.
637*a164e4c8SXin Li               if (log_delta > max_delta_msd) log_delta = max_delta_msd;
638*a164e4c8SXin Li             log_delta -= extra_prec;
639*a164e4c8SXin Li             CR delta = ONE.shiftLeft(log_delta);
640*a164e4c8SXin Li 
641*a164e4c8SXin Li             CR left = arg.subtract(delta);
642*a164e4c8SXin Li             CR right = arg.add(delta);
643*a164e4c8SXin Li             CR f_left = f[0].execute(left);
644*a164e4c8SXin Li             CR f_right = f[0].execute(right);
645*a164e4c8SXin Li             CR left_deriv = f_arg.subtract(f_left).shiftRight(log_delta);
646*a164e4c8SXin Li             CR right_deriv = f_right.subtract(f_arg).shiftRight(log_delta);
647*a164e4c8SXin Li             int eval_prec = p - extra_prec;
648*a164e4c8SXin Li             BigInteger appr_left_deriv = left_deriv.get_appr(eval_prec);
649*a164e4c8SXin Li             BigInteger appr_right_deriv = right_deriv.get_appr(eval_prec);
650*a164e4c8SXin Li             BigInteger deriv_difference =
651*a164e4c8SXin Li                 appr_right_deriv.subtract(appr_left_deriv).abs();
652*a164e4c8SXin Li             if (deriv_difference.compareTo(big8) < 0) {
653*a164e4c8SXin Li                 return scale(appr_left_deriv, -extra_prec);
654*a164e4c8SXin Li             } else {
655*a164e4c8SXin Li                 if (Thread.interrupted() || please_stop)
656*a164e4c8SXin Li                     throw new AbortedException();
657*a164e4c8SXin Li                 deriv2_msd[0] =
658*a164e4c8SXin Li                         eval_prec + deriv_difference.bitLength() + 4/*slop*/;
659*a164e4c8SXin Li                 deriv2_msd[0] -= log_delta;
660*a164e4c8SXin Li                 return approximate(p);
661*a164e4c8SXin Li             }
662*a164e4c8SXin Li         }
663*a164e4c8SXin Li     }
execute(CR x)664*a164e4c8SXin Li     public CR execute(CR x) {
665*a164e4c8SXin Li         return new monotoneDerivativeCR(x);
666*a164e4c8SXin Li     }
667*a164e4c8SXin Li }
668