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