xref: /netbsd-src/external/bsd/bc/dist/libmath.b (revision ed857e95db3fec367bb6764523110eb0ac99cb49)
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