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