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