3 ### Funcs.BC - a large number of functions for use with GNU BC
5 ## Not to be regarded as suitable for any purpose
6 ## Not guaranteed to return correct answers
11 if(scale==(s=scale(pi_)))return pi_
12 if(scale<s)return pi_/1
13 scale+=5;pi_=a(1)*4;scale-=5
17 define phi(){return((1+sqrt(5))/2)} ; phi = phi()
18 define psi(){return((1-sqrt(5))/2)} ; psi = psi()
23 ## Integer and Rounding
25 # Round to next integer nearest 0: -1.99 -> 1, 0.99 -> 0
26 define int(x) { auto os;os=scale;scale=0;x/=1;scale=os;return(x) }
28 # Round down to integer below x
30 auto os,xx;os=scale;scale=0
35 # Round up to integer above x
37 auto os,xx;x=-x;os=scale;scale=0
42 # Fractional part of x: 12.345 -> 0.345
44 auto os,xx;os=scale;scale=0
50 define abs(x) { if(x<0)return(-x)else return(x) }
53 define sgn(x) { if(x<0)return(-1)else if(x>0)return(1);return(0) }
55 # Round x up to next multiple of y
56 define round_up( x,y) { return(y*ceil( x/y )) }
58 # Round x down to previous multiple of y
59 define round_down(x,y) { return(y*floor(x/y )) }
61 # Round x to the nearest multiple of y
71 # Find the remainder of x/y
72 define int_remainder(x,y) {
79 define remainder(x,y) {
81 if(x==x/1&&y==y/1){scale=os;return int_remainder(x,y)}
83 return(x-round_down(x,y))
86 # Greatest common divisor of x and y
91 while(y>0){r=x%y;x=y;y=r}
98 if(x==x/1&&y==y/1){scale=os;return int_gcd(x,y)}
100 while(y>0){r=remainder(x,y);x=y;y=r}
104 # Lowest common multiple of x and y
105 define int_lcm(x,y) {
110 while(y>0){r=x%y;x=y;y=r}
115 define lcm(x,y) { return (x*y/gcd(x,y)) }
117 # Remove largest possible power of 2 from x
120 os=scale;scale=0;x/=1
121 if(x==0){scale=os;return 1}
126 # Largest power of 2 in x
134 ## Trig / Hyperbolic Trig
137 define sin(x) { return s(x) } # alias for standard library
139 define c(x) { return s(x+pi()/2) } # as fast or faster than
140 define cos(x) { return c(x) } # . standard library
142 define tan(x) { auto c;c=c(x);if(c==0)c=A^-scale;return(s(x)/c) }
145 define sec(x) { auto c;c=c(x);if(c==0)c=A^-scale;return( 1/c) }
147 define cosec(x) { auto s;s=s(x);if(s==0)s=A^-scale;return( 1/s) }
149 define cotan(x) { auto s;s=s(x);if(s==0)s=A^-scale;return(c(x)/s) }
152 define arcsin(x) { if(x==-1||x==1)return(pi()/2*x);return( a(x/sqrt(1-x*x)) ) }
154 define arccos(x) { if(x==0)return(0);return pi()/2-arcsin(x) }
156 # Arctangent (one argument)
157 define arctan(x) { return a(x) } # alias for standard library
159 # Arctangent (two arguments)
160 define arctan2(x,y) {
162 if(x==0&&y==0)return(0)
163 p=(1-sgn(y))*pi()*(2*(x>=0)-1)/2
164 if(x==0||y==0)return(p)
169 define arcsec(x) { return( a(x/sqrt(x*x-1)) ) }
171 define arccosec(x) { return( a(x/sqrt(x*x-1))+pi()*(sgn(x)-1)/2 ) }
172 # Arccotangent (one argument)
173 define arccotan(x) { return( a(x)+pi()/2 ) }
174 # Arccotangent (two arguments)
175 define arccotan2(x,y) { return( arctan(x,y)+pi()/2 ) }
178 define sinh(x) { auto t;t=e(x);return((t-1/t)/2) }
180 define cosh(x) { auto t;t=e(x);return((t+1/t)/2) }
182 define tanh(x) { auto t;t=e(x+x)-1;return(t/(t+2)) }
185 define sech(x) { auto t;t=e(x);return(2/(t+1/t)) }
186 # Hyperbolic Cosecant
187 define cosech(x) { auto t;t=e(x);return(2/(t-1/t)) }
188 # Hyperbolic Cotangent
189 define coth(x) { auto t;t=e(x+x)-1;return((t+2)/t) }
192 define arcsinh(x) { return( l(x+sqrt(x*x+1)) ) }
193 # Hyperbolic Arccosine
194 define arccosh(x) { return( l(x+sqrt(x*x-1)) ) }
195 # Hyperbolic Arctangent
196 define arctanh(x) { return( l((1+x)/(1-x))/2 ) }
198 # Hyperbolic Arcsecant
199 define arcsech(x) { return( l((sqrt(1-x*x)+1)/x) ) }
200 # Hyperbolic Arccosecant
201 define arccosech(x) { return( l((sqrt(1+x*x)*sgn(x)+1)/x) ) }
202 # Hyperbolic Arccotangent
203 define arccoth(x) { return( l((x+1)/(x-1))/2 ) }
205 # Length of the diagonal vector (0,0)-(x,y) [pythagoras]
206 define pyth(x,y) { return(sqrt(x*x+y*y)) }
207 define pyth3(x,y,z) { return(sqrt(x*x+y*y+z*z)) }
209 # Gudermannian Function
210 define gudermann(x) { return 2*(a(e(x))-a(1)) }
211 # Inverse Gudermannian Function
212 define arcgudermann(x) {
217 define besselj(n,x) { return j(n,x) } # alias for standard library
219 ## Exponential / Logs
222 define exp(x) { return e(x) } # alias for standard library
224 # Natural Logarithm (base e)
227 if(x< 0){print "ln error: logarithm of a negative number\n";return 0}
228 if(x==0)print "ln error: logarithm of zero; negative infinity\n"
229 len=length(x)-scale(x)-1
230 if(len<A)return l(x);
231 os=scale;scale+=length(len)+1
232 ln=l(x/A^len)+len*l(A)
235 } # speed improvement on standard library
237 # workhorse function for pow and log - new, less clever version
238 # Helps determine whether a fractional power is legitimate for a negative number
239 # . expects to be fed a positive value
240 # . returns -odd for even/odd; odd2 for odd1/odd2;
241 # even for odd/even; -2 for irrational
242 # . note that the return value is the denominator of the fraction if the
243 # fraction is rational, and the sign of the return value states whether
244 # the numerator is odd (positive) or even (negative)
245 # . since even/even is not possible, -2 is used to signify irrational
247 auto os,oib,es,eps,lim,max,p,max2,i,cf[],f[],n,d,t;
251 .=cf_new(cf[],y);if(scale(cf[0]))return -2;
252 .=frac_from_cf(f[],cf[],1)
253 d=f[0];scale=0;if(f[1]%2==0)d=-d;scale=os
267 if(d<eps){t=2*(n%2)-1;scale=os;ibase=oib;return t}#integers are x/1
269 # Find numerator and denominator of fraction, if any
270 lim=A*A;max2=A^5*(max=A^int(os/2));p=1
273 scale=es;y=1/y;scale=0
274 y-=(t=cf[++i]=y/1);p*=1+t
275 if(i>lim||(max<p&&p<max2)){cf[i=1]=-2;break}#escape if number seems irrational
276 if((p>max2||3*length(t)>es+es)&&i>1){cf[i--]=0;break}#cheat: assume rational
277 if(y==0)break;#completely rational
280 if(i==0){print "id_frac2_: something is wrong; y=",y,", d=",d,"\n"}
281 if(d!=-2&&i)while(--i){d=n+cf[i]*(t=d);n=t}
282 if(d<A^os){d*=2*(n%2)-1}else{d=-2}
287 # raise x to integer power y faster than bc's x^y
288 # . it seems bc (at time of writing) uses
289 # . an O(n) repeated multiplication algorithm
290 # . for the ^ operator, which is inefficient given
291 # . that there is a simple O(log n) alternative:
292 define fastintpow__(x,y) {
296 r=fastintpow__(x,hy=y/2)
300 define fastintpow_(x,y) {
302 if(y<0)return fastintpow_(1/x,-y)
307 if(x==-1){y%=2;y+=y;scale=os;return 1-y}
308 # bc is still faster for integers
309 if(x==(ix=x/1)){scale=os;return ix^y}
310 # ...and small no. of d.p.s, but not for values <= 2
311 if(scale(x)<3&&x>2){scale=os;return x^y}
312 scale=os;x/=1;scale=0
317 # Raise x to a fractional power faster than e^(y*l(x))
318 define fastfracpow_(x,y) {
320 inv=0;if(y<0){y=-y;inv=1}
323 if((yy=y*2^C)!=int(yy)){x=l(x);if(inv)x=-x;return e(y/1*x)}
324 # faster using square roots for rational binary fractions
325 # where denominator <= 8192
327 for(f=1;y&&x!=1;x=sqrt(x))if(y+=y>=1){.=y--;f*=x}
332 # Find the yth root of x where y is integer
333 define fastintroot_(x,y) {
335 os=scale;scale=0;y/=1;scale=os
338 if(y>=x-1){return fastfracpow_(x,1/y)}
339 if(y*int((d=2^F)/y)==d){
340 r=1;while(r+=r<=y)x=sqrt(x)
343 scale=length(y)-scale(y);if(scale<5)scale=5;r=e(ln(x)/y)
344 scale=os+5;if(scale<5)scale=5
348 d=r;r=(ys*r+x/fastintpow_(r,ys))/y
355 # Raise x to the y-th power
357 auto os,p,ix,iy,fy,dn,s;
360 if(0<x&&x<1){x=1/x;y=-y}
362 ix=x/1;iy=y/1;fy=y-iy;dn=0
363 scale=os;#scale=length(x/1)
365 dn=id_frac2_(y)# -ve implies even numerator
366 scale=0;if(dn%2){# odd denominator
368 if(dn<0)return pow(-x,y) # even/odd
369 /*else*/return -pow(-x,y) # odd/odd
372 if(dn>0) print "even root"
373 if(dn<0) print "irrational power"
374 print " of a negative number\n"
378 if(x==ix){p=fastintpow_(ix,iy);if(iy>0){scale=0;p/=1};scale=os;return p/1}
379 scale+=scale;p=fastintpow_(x,iy);scale=os;return p/1
381 if((dn=id_frac2_(y))!=-2){ #accurate rational roots (sometimes slower)
383 s=1;if(y<0){y=-y;s=-1}
384 p=y*dn+1/2;scale=0;p/=1;scale=os
385 if(p<A^3)x=fastintpow_(x,p)
387 if(p>=A^3)x=fastintpow_(x,p)
391 p=fastintpow_(ix,iy)*fastfracpow_(x,fy);
393 if(ix)p*=fastintpow_(x/ix,iy)
396 #The above is usually faster and more accurate than
397 # return( e(y*l(x)) );
400 # y-th root of x [ x^(1/y) ]
405 # Specific cube root function
406 # = stripped down version of fastintroot_(x,3)
409 if(x<0)return -cbrt(-x)
411 os=scale;scale=0;eps=A^(scale/3)
412 if(x<eps){scale=os;return 1/cbrt(1/x)}
414 scale=os+5;if(scale<5)scale=5
417 d=r;r=(r+r+x/(r*r))/3
424 # Logarithm of x in given base: log(2, 32) = 5 because 2^5 = 32
425 # tries to return a real answer where possible when given negative numbers
426 # e.g. log(-2, 64) = 6 because (-2)^6 = 64
427 # likewise log(-2,-128) = 7 because (-2)^7 = -128
429 auto os,i,l,sx,dn,dnm2;
431 if(x==0){print "log error: logarithm of zero; negative infinity\n"; return l(0)}
433 if(base==0){print "log error: zero-based logarithm\n"; return 0 }
434 if(base==1){print "log error: one-based logarithm; positive infinity\n";return -l(0)}
436 if((-1<base&&base<0)||(0<base&&base<1)){x=-log(1/base,x);scale-=6;return x/1}
437 if((-1<x && x<0)||(0<x && x<1)){x=-log(base,1/x);scale-=6;return x/1}
439 sx=1;if(x<0){x=-x;sx=-1}
442 os=scale;scale=0;dnm2=dn%2;scale=os
443 if(dnm2&&dn*sx<0){scale-=6;return l/1}
444 print "log error: -ve base: "
445 if(dnm2)print "wrong sign for "
447 if(dnm2)print "odd root/integer power\n"
449 if(dn!=-2)print "even root\n"
450 if(dn==-2)print "irrational power\n"
455 print "log error: +ve base: logarithm of a negative number\n"
458 x=ln(x)/ln(base);scale-=6;return x/1
461 # Integer-only logarithm of x in given base
462 # (compare digits function in digits.bc)
463 define int_log(base,x) {
465 if(0<x&&x<1) {return -int_log(base,1/x)}
466 os=scale;scale=0;base/=1;x/=1
467 if(base<2)base=ibase;
468 if(x==0) {scale=os;return 1-base*A^os}
469 if(x<base) {scale=os;return 0 }
470 c=length(x) # cheat and use what bc knows about decimal length
471 if(base==A){scale=os;return c-1}
472 if(base<A){if(x>A){c*=int_log(base,A);c-=2*(base<4)}else{c=0}}else{c/=length(base)+1}
473 p=base^c;while(p<=x){.=c++;p*=base}
477 # Lambert's W function 0 branch; Numerically solves w*e(w) = x for w
478 # * is slow to converge near -1/e at high scales
479 define lambertw0(x) {
480 auto oib, a, b, w, ow, lx, ew, e1, eps;
485 print "lambertw0: expected argument in range [-1/e,oo)\n"
489 if (x==ew) {ibase=oib;return -1}
490 # First approximation from :
491 # http://www.desy.de/~t00fri/qcdins/texhtml/lambertw/
492 # (A. Ringwald and F. Schrempp)
497 lx=l(x+1);w=0.665*(1+0.0195*lx)*lx+0.04
498 } else if((lx=length(x)-scale(x))>5000) {
499 lx*=l(A);w=lx-(1-1/lx)*l(lx)
501 lx=l(x);w=l(x-4)-(1-1/lx)*l(lx)
503 # Iteration adapted from code found on Wikipedia
504 # apparently by an anonymous user at 147.142.207.26
505 # and later another at 87.68.32.52
510 while(abs(ow-w)>eps&&w>-1){
512 if(x>0){ew=pow(e1,w)}else{ew=e(w)}
517 b = b/a - 1 + 1/(w+1)
526 # Lambert's W function -1 branch; Numerically solves w*e(w) = x for w
527 # * is slow to converge near -1/e at high scales
528 define lambertw_1(x) {
529 auto oib,os,oow,ow,w,ew,eps,d,iters;
533 print "lambertw_1: expected argument in [-1/e,0)\n"
535 if(x==0)return 1-A^scale
549 while(abs(ow-w)>eps){
552 w=(x*e(-w)+w*w)/(w+1)
553 if(iters++==A+A||oow==w){iters=0;w-=A^-scale;scale+=2}
559 # LambertW wrapper; takes most useful branch based on x
560 # to pick a branch manually, use lambertw_1 or lambertw0 directly
562 if(x<0)return lambertw_1(x)
566 # Faster calculation of lambertw0(exp(x))
567 # . avoids large intermediate value and associated slowness
568 # . numerically solves x = y+ln(y) for y
569 define lambertw0_exp(x) {
571 # Actual calculation is faster for x < 160 or thereabouts
572 if(x<C*D)return lambertw0(e(x));
573 oy=0;y=l(x);y=x-y+y/x;eps=A^-scale
574 while(abs(oy-y)>eps)y=x-l(oy=y)
578 # Shorthand alias for the above
579 define w_e(x){ return lambertw0_exp(x) }
581 # Numerically solve pow(y,y) = x for y
585 print "powroot error: attempt to solve for zero\n"
588 if(x==1||x==-1) {return x}
590 print "powroot error: unimplemented for values\n <0";r
598 ## Triangular numbers
600 # xth triangular number
603 x=x*(x+1)/2;xx=int(x)
608 # 'triangular root' of x
611 x=(sqrt(1+8*x)-1)/2;xx=int(x)
616 # Workhorse for following 2 functions
617 define tri_step_(t,s) {
619 t=t+(1+s*sqrt(1+8*t))/2;tt=int(t)
624 # Turn tri(x) into tri(x+1) without knowing x
626 return(tri_step_(t,0+1))
629 # Turn tri(x) into tri(x-1) without knowing x
631 return(tri_step_(t,0-1))
636 # the xth s-gonal number:
637 # e.g. poly(3, 4) = tri(4) = 1+2+3+4 = 10; poly(4, x) = x*x, etc
640 x*=(s/2-1)*(x-1)+1;xx=int(x);if(x==xx)x=xx
644 # inverse of the above = polygonal root:
645 # e.g. inverse_poly(3,x)=trirt(x); inverse_poly(4,x)=sqrt(x), etc
646 define inverse_poly(s, r) {
649 r=(sqrt(8*s*r+t*t)+t)/s/2;xx=int(r);if(r==xx)r=xx
653 # converse of poly(); solves poly(s,x)=r for s
654 # i.e. if the xth polygonal number is r, how many sides has the polygon?
655 # e.g. if the 5th polygonal number is 15, converse_poly(5,15) = 3
656 # so the polygon must have 3 sides! (15 is the 5th triangular number)
657 define converse_poly(x,r) {
659 x=2*((r/x-1)/(x-1)+1);xx=int(x);if(x==xx)x=xx
663 ## Tetrahedral numbers
665 # nth tetrahedral number
666 define tet(n) { return n*(n+1)*(n+2)/6 }
668 # tetrahedral root = inverse of the above
672 if(t<0)return -2-tetrt(-t)
674 if(k<0){print "tetrt: unimplemented for 0<|t|<sqrt(3^-5)\n"; return 0}
676 k=cbrt(sqrt(3*k)+3^3*t)
677 return k/c3^2+1/(c3*k)-1
680 ## Arithmetic-Geometric mean
682 define arigeomean(a,b) {
685 s=1;if(a<0&&b<0){s=-1;a=-a;b=-b}
686 if(a<0||b<0){print "arigeomean: mismatched signs\n";return 0}
687 while(a!=b){c=(a+b)/2;a=sqrt(a*b);b=c}
691 # solve n = arigeomean(x,y)
692 define inv_arigeomean(n, y){
693 auto ns,ox,x,b,c,d,i,s,eps;
695 s=1;if(n<0&&y<0){s=-1;n=-n;y=-y}
696 if(n<0||y<0){print "inv_arigeomean: mismatched signs\n";return 0}
699 scale+=2;eps=A^-scale;scale+=4
703 # try to force quadratic convergence
704 if(abs(x-ox)<eps){i=-1;break}
706 b=x+x/n*(n-arigeomean(1,x));
707 c=b+b/n*(n-arigeomean(1,b));
709 if(d){x=(b*b-c*x)/d}else{x=b;i=-1;break}
713 # give up and converge linearly
715 while(abs(x-ox)>eps){ox=x;x+=x/n*(n-arigeomean(1,x))}
718 scale-=6;return x*y/s