1*ed857e95Sphil/* $NetBSD: libmath.b,v 1.1 2017/04/10 02:28:23 phil Exp $ */ 2*ed857e95Sphil 3*ed857e95Sphil/* 4*ed857e95Sphil * Copyright (C) 1991-1994, 1997, 2006, 2008, 2012-2017 Free Software Foundation, Inc. 5*ed857e95Sphil * Copyright (C) 2016-2017 Philip A. Nelson. 6*ed857e95Sphil * All rights reserved. 7*ed857e95Sphil * 8*ed857e95Sphil * Redistribution and use in source and binary forms, with or without 9*ed857e95Sphil * modification, are permitted provided that the following conditions 10*ed857e95Sphil * are met: 11*ed857e95Sphil * 12*ed857e95Sphil * 1. Redistributions of source code must retain the above copyright 13*ed857e95Sphil * notice, this list of conditions and the following disclaimer. 14*ed857e95Sphil * 2. Redistributions in binary form must reproduce the above copyright 15*ed857e95Sphil * notice, this list of conditions and the following disclaimer in the 16*ed857e95Sphil * documentation and/or other materials provided with the distribution. 17*ed857e95Sphil * 3. The names Philip A. Nelson and Free Software Foundation may not be 18*ed857e95Sphil * used to endorse or promote products derived from this software 19*ed857e95Sphil * without specific prior written permission. 20*ed857e95Sphil * 21*ed857e95Sphil * THIS SOFTWARE IS PROVIDED BY PHILIP A. NELSON ``AS IS'' AND ANY EXPRESS OR 22*ed857e95Sphil * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 23*ed857e95Sphil * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 24*ed857e95Sphil * IN NO EVENT SHALL PHILIP A. NELSON OR THE FREE SOFTWARE FOUNDATION BE 25*ed857e95Sphil * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 26*ed857e95Sphil * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 27*ed857e95Sphil * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 28*ed857e95Sphil * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 29*ed857e95Sphil * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 30*ed857e95Sphil * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 31*ed857e95Sphil * THE POSSIBILITY OF SUCH DAMAGE. 32*ed857e95Sphil */ 33*ed857e95Sphil 34*ed857e95Sphil/* libmath.b for bc. */ 35*ed857e95Sphil 36*ed857e95Sphilscale = 20 37*ed857e95Sphil 38*ed857e95Sphil/* Uses the fact that e^x = (e^(x/2))^2 39*ed857e95Sphil When x is small enough, we use the series: 40*ed857e95Sphil e^x = 1 + x + x^2/2! + x^3/3! + ... 41*ed857e95Sphil*/ 42*ed857e95Sphil 43*ed857e95Sphildefine e(x) { 44*ed857e95Sphil auto a, b, d, e, f, i, m, n, v, z 45*ed857e95Sphil 46*ed857e95Sphil /* a - holds x^y of x^y/y! */ 47*ed857e95Sphil /* d - holds y! */ 48*ed857e95Sphil /* e - is the value x^y/y! */ 49*ed857e95Sphil /* v - is the sum of the e's */ 50*ed857e95Sphil /* f - number of times x was divided by 2. */ 51*ed857e95Sphil /* m - is 1 if x was minus. */ 52*ed857e95Sphil /* i - iteration count. */ 53*ed857e95Sphil /* n - the scale to compute the sum. */ 54*ed857e95Sphil /* z - orignal scale. */ 55*ed857e95Sphil /* b - holds the original ibase. */ 56*ed857e95Sphil 57*ed857e95Sphil /* Non base 10 ibase? */ 58*ed857e95Sphil if (ibase != A) { 59*ed857e95Sphil b = ibase; 60*ed857e95Sphil ibase = A; 61*ed857e95Sphil v = e(x); 62*ed857e95Sphil ibase = b; 63*ed857e95Sphil return (v); 64*ed857e95Sphil } 65*ed857e95Sphil 66*ed857e95Sphil /* Check the sign of x. */ 67*ed857e95Sphil if (x<0) { 68*ed857e95Sphil m = 1 69*ed857e95Sphil x = -x 70*ed857e95Sphil } 71*ed857e95Sphil 72*ed857e95Sphil /* Precondition x. */ 73*ed857e95Sphil z = scale; 74*ed857e95Sphil n = 6 + z + .44*x; 75*ed857e95Sphil scale = scale(x)+1; 76*ed857e95Sphil while (x > 1) { 77*ed857e95Sphil f += 1; 78*ed857e95Sphil x /= 2; 79*ed857e95Sphil scale += 1; 80*ed857e95Sphil } 81*ed857e95Sphil 82*ed857e95Sphil /* Initialize the variables. */ 83*ed857e95Sphil scale = n; 84*ed857e95Sphil v = 1+x 85*ed857e95Sphil a = x 86*ed857e95Sphil d = 1 87*ed857e95Sphil 88*ed857e95Sphil for (i=2; 1; i++) { 89*ed857e95Sphil e = (a *= x) / (d *= i) 90*ed857e95Sphil if (e == 0) { 91*ed857e95Sphil if (f>0) while (f--) v = v*v; 92*ed857e95Sphil scale = z 93*ed857e95Sphil if (m) return (1/v); 94*ed857e95Sphil return (v/1); 95*ed857e95Sphil } 96*ed857e95Sphil v += e 97*ed857e95Sphil } 98*ed857e95Sphil} 99*ed857e95Sphil 100*ed857e95Sphil/* Natural log. Uses the fact that ln(x^2) = 2*ln(x) 101*ed857e95Sphil The series used is: 102*ed857e95Sphil ln(x) = 2(a+a^3/3+a^5/5+...) where a=(x-1)/(x+1) 103*ed857e95Sphil*/ 104*ed857e95Sphil 105*ed857e95Sphildefine l(x) { 106*ed857e95Sphil auto b, e, f, i, m, n, v, z 107*ed857e95Sphil 108*ed857e95Sphil /* Non base 10 ibase? */ 109*ed857e95Sphil if (ibase != A) { 110*ed857e95Sphil b = ibase; 111*ed857e95Sphil ibase = A; 112*ed857e95Sphil v = l(x); 113*ed857e95Sphil ibase = b; 114*ed857e95Sphil return (v); 115*ed857e95Sphil } 116*ed857e95Sphil 117*ed857e95Sphil /* return something for the special case. */ 118*ed857e95Sphil if (x <= 0) return ((1 - 10^scale)/1) 119*ed857e95Sphil 120*ed857e95Sphil /* Precondition x to make .5 < x < 2.0. */ 121*ed857e95Sphil z = scale; 122*ed857e95Sphil scale = 6 + scale; 123*ed857e95Sphil f = 2; 124*ed857e95Sphil i=0 125*ed857e95Sphil while (x >= 2) { /* for large numbers */ 126*ed857e95Sphil f *= 2; 127*ed857e95Sphil x = sqrt(x); 128*ed857e95Sphil } 129*ed857e95Sphil while (x <= .5) { /* for small numbers */ 130*ed857e95Sphil f *= 2; 131*ed857e95Sphil x = sqrt(x); 132*ed857e95Sphil } 133*ed857e95Sphil 134*ed857e95Sphil /* Set up the loop. */ 135*ed857e95Sphil v = n = (x-1)/(x+1) 136*ed857e95Sphil m = n*n 137*ed857e95Sphil 138*ed857e95Sphil /* Sum the series. */ 139*ed857e95Sphil for (i=3; 1; i+=2) { 140*ed857e95Sphil e = (n *= m) / i 141*ed857e95Sphil if (e == 0) { 142*ed857e95Sphil v = f*v 143*ed857e95Sphil scale = z 144*ed857e95Sphil return (v/1) 145*ed857e95Sphil } 146*ed857e95Sphil v += e 147*ed857e95Sphil } 148*ed857e95Sphil} 149*ed857e95Sphil 150*ed857e95Sphil/* Sin(x) uses the standard series: 151*ed857e95Sphil sin(x) = x - x^3/3! + x^5/5! - x^7/7! ... */ 152*ed857e95Sphil 153*ed857e95Sphildefine s(x) { 154*ed857e95Sphil auto b, e, i, m, n, s, v, z 155*ed857e95Sphil 156*ed857e95Sphil /* Non base 10 ibase? */ 157*ed857e95Sphil if (ibase != A) { 158*ed857e95Sphil b = ibase; 159*ed857e95Sphil ibase = A; 160*ed857e95Sphil v = s(x); 161*ed857e95Sphil ibase = b; 162*ed857e95Sphil return (v); 163*ed857e95Sphil } 164*ed857e95Sphil 165*ed857e95Sphil /* precondition x. */ 166*ed857e95Sphil z = scale 167*ed857e95Sphil scale = 1.1*z + 2; 168*ed857e95Sphil v = a(1) 169*ed857e95Sphil if (x < 0) { 170*ed857e95Sphil m = 1; 171*ed857e95Sphil x = -x; 172*ed857e95Sphil } 173*ed857e95Sphil scale = 0 174*ed857e95Sphil n = (x / v + 2 )/4 175*ed857e95Sphil x = x - 4*n*v 176*ed857e95Sphil if (n%2) x = -x 177*ed857e95Sphil 178*ed857e95Sphil /* Do the loop. */ 179*ed857e95Sphil scale = z + 2; 180*ed857e95Sphil v = e = x 181*ed857e95Sphil s = -x*x 182*ed857e95Sphil for (i=3; 1; i+=2) { 183*ed857e95Sphil e *= s/(i*(i-1)) 184*ed857e95Sphil if (e == 0) { 185*ed857e95Sphil scale = z 186*ed857e95Sphil if (m) return (-v/1); 187*ed857e95Sphil return (v/1); 188*ed857e95Sphil } 189*ed857e95Sphil v += e 190*ed857e95Sphil } 191*ed857e95Sphil} 192*ed857e95Sphil 193*ed857e95Sphil/* Cosine : cos(x) = sin(x+pi/2) */ 194*ed857e95Sphildefine c(x) { 195*ed857e95Sphil auto b, v, z; 196*ed857e95Sphil 197*ed857e95Sphil /* Non base 10 ibase? */ 198*ed857e95Sphil if (ibase != A) { 199*ed857e95Sphil b = ibase; 200*ed857e95Sphil ibase = A; 201*ed857e95Sphil v = c(x); 202*ed857e95Sphil ibase = b; 203*ed857e95Sphil return (v); 204*ed857e95Sphil } 205*ed857e95Sphil 206*ed857e95Sphil z = scale; 207*ed857e95Sphil scale = scale*1.2; 208*ed857e95Sphil v = s(x+a(1)*2); 209*ed857e95Sphil scale = z; 210*ed857e95Sphil return (v/1); 211*ed857e95Sphil} 212*ed857e95Sphil 213*ed857e95Sphil/* Arctan: Using the formula: 214*ed857e95Sphil atan(x) = atan(c) + atan((x-c)/(1+xc)) for a small c (.2 here) 215*ed857e95Sphil For under .2, use the series: 216*ed857e95Sphil atan(x) = x - x^3/3 + x^5/5 - x^7/7 + ... */ 217*ed857e95Sphil 218*ed857e95Sphildefine a(x) { 219*ed857e95Sphil auto a, b, e, f, i, m, n, s, v, z 220*ed857e95Sphil 221*ed857e95Sphil /* a is the value of a(.2) if it is needed. */ 222*ed857e95Sphil /* f is the value to multiply by a in the return. */ 223*ed857e95Sphil /* e is the value of the current term in the series. */ 224*ed857e95Sphil /* v is the accumulated value of the series. */ 225*ed857e95Sphil /* m is 1 or -1 depending on x (-x -> -1). results are divided by m. */ 226*ed857e95Sphil /* i is the denominator value for series element. */ 227*ed857e95Sphil /* n is the numerator value for the series element. */ 228*ed857e95Sphil /* s is -x*x. */ 229*ed857e95Sphil /* z is the saved user's scale. */ 230*ed857e95Sphil 231*ed857e95Sphil /* Non base 10 ibase? */ 232*ed857e95Sphil if (ibase != A) { 233*ed857e95Sphil b = ibase; 234*ed857e95Sphil ibase = A; 235*ed857e95Sphil v = a(x); 236*ed857e95Sphil ibase = b; 237*ed857e95Sphil return (v); 238*ed857e95Sphil } 239*ed857e95Sphil 240*ed857e95Sphil /* Negative x? */ 241*ed857e95Sphil m = 1; 242*ed857e95Sphil if (x<0) { 243*ed857e95Sphil m = -1; 244*ed857e95Sphil x = -x; 245*ed857e95Sphil } 246*ed857e95Sphil 247*ed857e95Sphil /* Special case and for fast answers */ 248*ed857e95Sphil if (x==1) { 249*ed857e95Sphil if (scale <= 25) return (.7853981633974483096156608/m) 250*ed857e95Sphil if (scale <= 40) return (.7853981633974483096156608458198757210492/m) 251*ed857e95Sphil if (scale <= 60) \ 252*ed857e95Sphil return (.785398163397448309615660845819875721049292349843776455243736/m) 253*ed857e95Sphil } 254*ed857e95Sphil if (x==.2) { 255*ed857e95Sphil if (scale <= 25) return (.1973955598498807583700497/m) 256*ed857e95Sphil if (scale <= 40) return (.1973955598498807583700497651947902934475/m) 257*ed857e95Sphil if (scale <= 60) \ 258*ed857e95Sphil return (.197395559849880758370049765194790293447585103787852101517688/m) 259*ed857e95Sphil } 260*ed857e95Sphil 261*ed857e95Sphil 262*ed857e95Sphil /* Save the scale. */ 263*ed857e95Sphil z = scale; 264*ed857e95Sphil 265*ed857e95Sphil /* Note: a and f are known to be zero due to being auto vars. */ 266*ed857e95Sphil /* Calculate atan of a known number. */ 267*ed857e95Sphil if (x > .2) { 268*ed857e95Sphil scale = z+5; 269*ed857e95Sphil a = a(.2); 270*ed857e95Sphil } 271*ed857e95Sphil 272*ed857e95Sphil /* Precondition x. */ 273*ed857e95Sphil scale = z+3; 274*ed857e95Sphil while (x > .2) { 275*ed857e95Sphil f += 1; 276*ed857e95Sphil x = (x-.2) / (1+x*.2); 277*ed857e95Sphil } 278*ed857e95Sphil 279*ed857e95Sphil /* Initialize the series. */ 280*ed857e95Sphil v = n = x; 281*ed857e95Sphil s = -x*x; 282*ed857e95Sphil 283*ed857e95Sphil /* Calculate the series. */ 284*ed857e95Sphil for (i=3; 1; i+=2) { 285*ed857e95Sphil e = (n *= s) / i; 286*ed857e95Sphil if (e == 0) { 287*ed857e95Sphil scale = z; 288*ed857e95Sphil return ((f*a+v)/m); 289*ed857e95Sphil } 290*ed857e95Sphil v += e 291*ed857e95Sphil } 292*ed857e95Sphil} 293*ed857e95Sphil 294*ed857e95Sphil 295*ed857e95Sphil/* Bessel function of integer order. Uses the following: 296*ed857e95Sphil j(-n,x) = (-1)^n*j(n,x) 297*ed857e95Sphil j(n,x) = x^n/(2^n*n!) * (1 - x^2/(2^2*1!*(n+1)) + x^4/(2^4*2!*(n+1)*(n+2)) 298*ed857e95Sphil - x^6/(2^6*3!*(n+1)*(n+2)*(n+3)) .... ) 299*ed857e95Sphil*/ 300*ed857e95Sphildefine j(n,x) { 301*ed857e95Sphil auto a, b, d, e, f, i, m, s, v, z 302*ed857e95Sphil 303*ed857e95Sphil /* Non base 10 ibase? */ 304*ed857e95Sphil if (ibase != A) { 305*ed857e95Sphil b = ibase; 306*ed857e95Sphil ibase = A; 307*ed857e95Sphil v = j(n,x); 308*ed857e95Sphil ibase = b; 309*ed857e95Sphil return (v); 310*ed857e95Sphil } 311*ed857e95Sphil 312*ed857e95Sphil /* Make n an integer and check for negative n. */ 313*ed857e95Sphil z = scale; 314*ed857e95Sphil scale = 0; 315*ed857e95Sphil n = n/1; 316*ed857e95Sphil if (n<0) { 317*ed857e95Sphil n = -n; 318*ed857e95Sphil if (n%2 == 1) m = 1; 319*ed857e95Sphil } 320*ed857e95Sphil 321*ed857e95Sphil /* Compute the factor of x^n/(2^n*n!) */ 322*ed857e95Sphil f = 1; 323*ed857e95Sphil for (i=2; i<=n; i++) f = f*i; 324*ed857e95Sphil scale = 1.5*z; 325*ed857e95Sphil f = x^n / 2^n / f; 326*ed857e95Sphil 327*ed857e95Sphil /* Initialize the loop .*/ 328*ed857e95Sphil v = e = 1; 329*ed857e95Sphil s = -x*x/4 330*ed857e95Sphil scale = 1.5*z + length(f) - scale(f); 331*ed857e95Sphil 332*ed857e95Sphil /* The Loop.... */ 333*ed857e95Sphil for (i=1; 1; i++) { 334*ed857e95Sphil e = e * s / i / (n+i); 335*ed857e95Sphil if (e == 0) { 336*ed857e95Sphil scale = z 337*ed857e95Sphil if (m) return (-f*v/1); 338*ed857e95Sphil return (f*v/1); 339*ed857e95Sphil } 340*ed857e95Sphil v += e; 341*ed857e95Sphil } 342*ed857e95Sphil} 343