Tempo estimado de leitura: 15 minutos
Modos de uso
First things first. Para começar com o bc
é importante saber que há 2 formas de utilizá-lo, pelo modo interativo ou não-interativo. Para usar o modo interativo é fácil, basta digitar bc
e iniciar os comandos.
$ bc bc 1.06 Copyright 1991-1994, 1997, 1998, 2000 Free Software Foundation, Inc. This is free software with ABSOLUTELY NO WARRANTY. For details type `warranty'. 1+1 2
No modo não-interativo, é necessário passar uma string para stdin do bc de alguma maneira. echo, printf, pipe, here strings… escolha a mais conveniente e toque pra frente. Vamos ver alguns exemplos:
$ echo "10*10" | bc #via pipe 100
$ bc <<< "10-3" #via here strings 7
Variáveis
O bc
tem 4 variáveis importantes que ele utiliza internamente:
ibase #base dos números de entrada (input) no cálculo obase #base do número do resultado (de saída, output) do cálculo scale #define a quantidade de dígitos após a vírgula após operações de divisão last #repete o último número calculado
Você também pode definir suas próprias variáveis, mas sempre em letras minúsculas.
$ bc bc 1.06 Copyright 1991-1994, 1997, 1998, 2000 Free Software Foundation, Inc. This is free software with ABSOLUTELY NO WARRANTY. For details type `warranty'.a = 1 b = 2 c = a + b c 3
O bc não tolera caixas altas nas variáveis, mas exige caixas altas para todas as entradas hexadecimais! Fique atento a isso =)
Conversão hexadecimal, decimal, octal, binário e afins…
Essa calculadora fica ainda mais interessante quando precisamos alterar as bases. Por exemplo, para converter hexadecimal (base 16) para decimal (base 10), basta alterar as variáveis ibase (input) e obase (output). Ambas são 10 por default. Então vamos trocar somente a ibase, já que a saída será decimal por padrão:
$ echo "ibase=16; FF" | bc 255
Ou ainda, para converter da base 16 (hex) para base 2 (binário) com os argumentos ibase
(input) e obase
(output) declarados juntos:
$ echo "ibase=16; obase=2; FF" | bc 11111111
Operadores
Os básicos:
+ adição
– subtração
* multiplicação
/ divisão
% resto
^ potência
Veja o bc em ação com alguns comandos e meus comentários ao lado (sim, ele aceita comentários usando # depois de cada comando). Para entrar no modo interativo, apenas chame pelo comando bc
.
$ bc -q 10*10 #cálculo com base 10, default 100 ibase=16 #alteração do input para base 16 (hex) FF 255 #output de FF FF*2 510 #output de FF*2 obase=2 #troca a base do output para 2 (binário) FF 11111111 #resultado de FF FF*2 111111110 #resultado de FF*2 ibase=2 #troca base do input para 2 obase=A #troca base do output para 10 (escrito em hex). Aqui tem uma pegadinha, se colocar 10 o BC irá se perder. obase #chama a variável obase 10 #exibe o valor que consta na variável obase, igual no python 🙂 11111111 255 #resultado de 11111111 em decimal last #exibe o último resultado 255 scale=3 #define os dígitos após vírgula 23/3 7.666 quit #sai do bc interativo
Outras funções
Precisa de mais? Logarítimo, seno, cosseno, tangente etc? Utilize a biblioteca matemática do bc com a opção –mathlib
$ bc --mathlib s(1) .84147098480789650665 c(1) .54030230586813971740 a(1) .78539816339744830961
E o bc ainda consegue fazer programas! Veja esse exemplo do manual do bc, o check book. Salve o código abaixo num arquivo qualquer, por exemplo checkbook.bc
scale=2 print "\nCheck book program!\n" print " Remember, deposits are negative transactions.\n" print " Exit by a 0 transaction.\n\n" print "Initial balance? "; bal = read() bal /= 1 print "\n" while (1) { "current balance = "; bal "transaction? "; trans = read() if (trans == 0) break; bal -= trans bal /= 1 } quit
Agora, execute-o.
$ bc -q checkbook.bc Check book program! Remember, deposits are negative transactions. Exit by a 0 transaction. Initial balance? 2 current balance = 2.00 transaction? 1 current balance = 1.00 transaction? 1 current balance = 0 transaction? 1 current balance = -1.00 transaction? 0 quit
Tem muitas outras funções no bc, vale a pena explorar mais se vc quiser mergulhar no assunto. O manual do bc é bem interessante, certamente vale dar uma olhada.
Mas antes de encerrar o artigo, dê uma olhada nesse arquivo gigante de funções para o bc!
#!/usr/local/bin/bc -l ### Funcs.BC - a large number of functions for use with GNU BC ## Not to be regarded as suitable for any purpose ## Not guaranteed to return correct answers scale=50; define pi() { auto s; if(scale==(s=scale(pi_)))return pi_ if(scale<s)return pi_/1 scale+=5;pi_=a(1)*4;scale-=5 return pi_/1 } e = e(1); define phi(){return((1+sqrt(5))/2)} ; phi = phi() define psi(){return((1-sqrt(5))/2)} ; psi = psi() # Reset base to ten obase=ibase=A; ## Integer and Rounding # Round to next integer nearest 0: -1.99 -> 1, 0.99 -> 0 define int(x) { auto os;os=scale;scale=0;x/=1;scale=os;return(x) } # Round down to integer below x define floor(x) { auto os,xx;os=scale;scale=0 xx=x/1;if(xx>x).=xx-- scale=os;return(xx) } # Round up to integer above x define ceil(x) { auto os,xx;x=-x;os=scale;scale=0 xx=x/1;if(xx>x).=xx-- scale=os;return(-xx) } # Fractional part of x: 12.345 -> 0.345 define frac(x) { auto os,xx;os=scale;scale=0 xx=x/1;if(xx>x).=xx-- scale=os;return(x-xx) } # Absolute value of x define abs(x) { if(x<0)return(-x)else return(x) } # Sign of x define sgn(x) { if(x<0)return(-1)else if(x>0)return(1);return(0) } # Round x up to next multiple of y define round_up( x,y) { return(y*ceil( x/y )) } # Round x down to previous multiple of y define round_down(x,y) { return(y*floor(x/y )) } # Round x to the nearest multiple of y define round( x,y) { auto os,oib; os=scale;oib=ibase .=scale++;ibase=A y*=floor(x/y+.5) ibase=oib;scale=os return y } # Find the remainder of x/y define int_remainder(x,y) { auto os; os=scale;scale=0 x/=1;y/=1;x%=y scale=os return(x) } define remainder(x,y) { os=scale;scale=0 if(x==x/1&&y==y/1){scale=os;return int_remainder(x,y)} scale=os return(x-round_down(x,y)) } # Greatest common divisor of x and y define int_gcd(x,y) { auto r,os; os=scale;scale=0 x/=1;y/=1 while(y>0){r=x%y;x=y;y=r} scale=os return(x) } define gcd(x,y) { auto r,os; os=scale;scale=0 if(x==x/1&&y==y/1){scale=os;return int_gcd(x,y)} scale=os while(y>0){r=remainder(x,y);x=y;y=r} return(x) } # Lowest common multiple of x and y define int_lcm(x,y) { auto r,m,os; os=scale;scale=0 x/=1;y/=1 m=x*y while(y>0){r=x%y;x=y;y=r} m/=x scale=os return(m) } define lcm(x,y) { return (x*y/gcd(x,y)) } # Remove largest possible power of 2 from x define oddpart(x){ auto os; os=scale;scale=0;x/=1 if(x==0){scale=os;return 1} while(!x%2)x/=2 scale=os;return x } # Largest power of 2 in x define evenpart(x) { auto os; os=scale;scale=0 x/=oddpart(x/1) scale=os;return x } ## Trig / Hyperbolic Trig # Sine define sin(x) { return s(x) } # alias for standard library # Cosine define c(x) { return s(x+pi()/2) } # as fast or faster than define cos(x) { return c(x) } # . standard library # Tangent define tan(x) { auto c;c=c(x);if(c==0)c=A^-scale;return(s(x)/c) } # Secant define sec(x) { auto c;c=c(x);if(c==0)c=A^-scale;return( 1/c) } # Cosecant define cosec(x) { auto s;s=s(x);if(s==0)s=A^-scale;return( 1/s) } # Cotangent define cotan(x) { auto s;s=s(x);if(s==0)s=A^-scale;return(c(x)/s) } # Arcsine define arcsin(x) { if(x==-1||x==1)return(pi()/2*x);return( a(x/sqrt(1-x*x)) ) } # Arccosine define arccos(x) { if(x==0)return(0);return pi()/2-arcsin(x) } # Arctangent (one argument) define arctan(x) { return a(x) } # alias for standard library # Arctangent (two arguments) define arctan2(x,y) { auto p; if(x==0&&y==0)return(0) p=(1-sgn(y))*pi()*(2*(x>=0)-1)/2 if(x==0||y==0)return(p) return(p+a(x/y)) } # Arcsecant define arcsec(x) { return( a(x/sqrt(x*x-1)) ) } # Arccosecant define arccosec(x) { return( a(x/sqrt(x*x-1))+pi()*(sgn(x)-1)/2 ) } # Arccotangent (one argument) define arccotan(x) { return( a(x)+pi()/2 ) } # Arccotangent (two arguments) define arccotan2(x,y) { return( arctan(x,y)+pi()/2 ) } # Hyperbolic Sine define sinh(x) { auto t;t=e(x);return((t-1/t)/2) } # Hyperbolic Cosine define cosh(x) { auto t;t=e(x);return((t+1/t)/2) } # Hyperbolic Tangent define tanh(x) { auto t;t=e(x+x)-1;return(t/(t+2)) } # Hyperbolic Secant define sech(x) { auto t;t=e(x);return(2/(t+1/t)) } # Hyperbolic Cosecant define cosech(x) { auto t;t=e(x);return(2/(t-1/t)) } # Hyperbolic Cotangent define coth(x) { auto t;t=e(x+x)-1;return((t+2)/t) } # Hyperbolic Arcsine define arcsinh(x) { return( l(x+sqrt(x*x+1)) ) } # Hyperbolic Arccosine define arccosh(x) { return( l(x+sqrt(x*x-1)) ) } # Hyperbolic Arctangent define arctanh(x) { return( l((1+x)/(1-x))/2 ) } # Hyperbolic Arcsecant define arcsech(x) { return( l((sqrt(1-x*x)+1)/x) ) } # Hyperbolic Arccosecant define arccosech(x) { return( l((sqrt(1+x*x)*sgn(x)+1)/x) ) } # Hyperbolic Arccotangent define arccoth(x) { return( l((x+1)/(x-1))/2 ) } # Length of the diagonal vector (0,0)-(x,y) [pythagoras] define pyth(x,y) { return(sqrt(x*x+y*y)) } define pyth3(x,y,z) { return(sqrt(x*x+y*y+z*z)) } # Gudermannian Function define gudermann(x) { return 2*(a(e(x))-a(1)) } # Inverse Gudermannian Function define arcgudermann(x) { return arctanh(s(x)) } # Bessel function define besselj(n,x) { return j(n,x) } # alias for standard library ## Exponential / Logs # Exponential e^x define exp(x) { return e(x) } # alias for standard library # Natural Logarithm (base e) define ln(x) { auto os,len,ln; if(x< 0){print "ln error: logarithm of a negative number\n";return 0} if(x==0)print "ln error: logarithm of zero; negative infinity\n" len=length(x)-scale(x)-1 if(len<A)return l(x); os=scale;scale+=length(len)+1 ln=l(x/A^len)+len*l(A) scale=os return ln/1 } # speed improvement on standard library # workhorse function for pow and log - new, less clever version # Helps determine whether a fractional power is legitimate for a negative number # . expects to be fed a positive value # . returns -odd for even/odd; odd2 for odd1/odd2; # even for odd/even; -2 for irrational # . note that the return value is the denominator of the fraction if the # fraction is rational, and the sign of the return value states whether # the numerator is odd (positive) or even (negative) # . since even/even is not possible, -2 is used to signify irrational define id_frac2_(y){ auto os,oib,es,eps,lim,max,p,max2,i,cf[],f[],n,d,t; os=scale if(cf_max){ # cf.bc is present! .=cf_new(cf[],y);if(scale(cf[0]))return -2; .=frac_from_cf(f[],cf[],1) d=f[0];scale=0;if(f[1]%2==0)d=-d;scale=os return d } oib=ibase;ibase=A scale=0 es=3*os/4 scale=os eps=A^-es y+=eps/A scale=es y/=1 scale=0 if(y<0)y=-y d=y-(n=y/1) if(d<eps){t=2*(n%2)-1;scale=os;ibase=oib;return t}#integers are x/1 t=y/2;t=y-t-t # Find numerator and denominator of fraction, if any lim=A*A;max2=A^5*(max=A^int(os/2));p=1 i=0;y=t while(1) { scale=es;y=1/y;scale=0 y-=(t=cf[++i]=y/1);p*=1+t if(i>lim||(max<p&&p<max2)){cf[i=1]=-2;break}#escape if number seems irrational if((p>max2||3*length(t)>es+es)&&i>1){cf[i--]=0;break}#cheat: assume rational if(y==0)break;#completely rational } n=1;d=cf[i] if(i==0){print "id_frac2_: something is wrong; y=",y,", d=",d,"\n"} if(d!=-2&&i)while(--i){d=n+cf[i]*(t=d);n=t} if(d<A^os){d*=2*(n%2)-1}else{d=-2} scale=os;ibase=oib return d; } # raise x to integer power y faster than bc's x^y # . it seems bc (at time of writing) uses # . an O(n) repeated multiplication algorithm # . for the ^ operator, which is inefficient given # . that there is a simple O(log n) alternative: define fastintpow__(x,y) { auto r,hy; if(y==0)return(1) if(y==1)return(x) r=fastintpow__(x,hy=y/2) r*=r;if(hy+hy<y)r*=x return( r ) } define fastintpow_(x,y) { auto ix,os; if(y<0)return fastintpow_(1/x,-y) if(y==0)return(1) if(y==1)return(x) if(x==1)return(1) os=scale;scale=0 if(x==-1){y%=2;y+=y;scale=os;return 1-y} # bc is still faster for integers if(x==(ix=x/1)){scale=os;return ix^y} # ...and small no. of d.p.s, but not for values <= 2 if(scale(x)<3&&x>2){scale=os;return x^y} scale=os;x/=1;scale=0 x=fastintpow__(x,y); scale=os;return x; } # Raise x to a fractional power faster than e^(y*l(x)) define fastfracpow_(x,y) { auto f,yy,inv; inv=0;if(y<0){y=-y;inv=1} y-=int(y) if(y==0)return 1; if((yy=y*2^C)!=int(yy)){x=l(x);if(inv)x=-x;return e(y/1*x)} # faster using square roots for rational binary fractions # where denominator <= 8192 x=sqrt(x) for(f=1;y&&x!=1;x=sqrt(x))if(y+=y>=1){.=y--;f*=x} if(inv)f=1/f; return f; } # Find the yth root of x where y is integer define fastintroot_(x,y) { auto os,d,r,ys,eps; os=scale;scale=0;y/=1;scale=os if(y<0){x=1/x;y=-y} if(y==1){return x} if(y>=x-1){return fastfracpow_(x,1/y)} if(y*int((d=2^F)/y)==d){ r=1;while(r+=r<=y)x=sqrt(x) return x } scale=length(y)-scale(y);if(scale<5)scale=5;r=e(ln(x)/y) scale=os+5;if(scale<5)scale=5 d=1;eps=A^(3-scale) ys=y-1 while(d>eps){ d=r;r=(ys*r+x/fastintpow_(r,ys))/y d-=r;if(d<0)d=-d } scale=os return r/1 } # Raise x to the y-th power define pow(x,y) { auto os,p,ix,iy,fy,dn,s; if(y==0) return 1 if(x==0) return 0 if(0<x&&x<1){x=1/x;y=-y} os=scale;scale=0 ix=x/1;iy=y/1;fy=y-iy;dn=0 scale=os;#scale=length(x/1) if(y!=iy&&x<0){ dn=id_frac2_(y)# -ve implies even numerator scale=0;if(dn%2){# odd denominator scale=os if(dn<0)return pow(-x,y) # even/odd /*else*/return -pow(-x,y) # odd/odd } print "pow error: " if(dn>0) print "even root" if(dn<0) print "irrational power" print " of a negative number\n" scale=os;return 0 } if(y==iy) { if(x==ix){p=fastintpow_(ix,iy);if(iy>0){scale=0;p/=1};scale=os;return p/1} scale+=scale;p=fastintpow_(x,iy);scale=os;return p/1 } if((dn=id_frac2_(y))!=-2){ #accurate rational roots (sometimes slower) if(dn<0)dn=-dn s=1;if(y<0){y=-y;s=-1} p=y*dn+1/2;scale=0;p/=1;scale=os if(p<A^3)x=fastintpow_(x,p) x=fastintroot_(x,dn) if(p>=A^3)x=fastintpow_(x,p) if(s<0)x=1/x return x } p=fastintpow_(ix,iy)*fastfracpow_(x,fy); scale=os+os if(ix)p*=fastintpow_(x/ix,iy) scale=os return p/1 #The above is usually faster and more accurate than # return( e(y*l(x)) ); } # y-th root of x [ x^(1/y) ] define root(x,y) { return pow(x,1/y) } # Specific cube root function # = stripped down version of fastintroot_(x,3) define cbrt(x) { auto os,d,r,eps; if(x<0)return -cbrt(-x) if(x==0)return 0 os=scale;scale=0;eps=A^(scale/3) if(x<eps){scale=os;return 1/cbrt(1/x)} scale=5;r=e(ln(x)/3) scale=os+5;if(scale<5)scale=5 d=1;eps=A^(3-scale) while(d>eps){ d=r;r=(r+r+x/(r*r))/3 d-=r;if(d<0)d=-d } scale=os return r/1 } # Logarithm of x in given base: log(2, 32) = 5 because 2^5 = 32 # tries to return a real answer where possible when given negative numbers # e.g. log(-2, 64) = 6 because (-2)^6 = 64 # likewise log(-2,-128) = 7 because (-2)^7 = -128 define log(base,x) { auto os,i,l,sx,dn,dnm2; if(base==x)return 1; if(x==0){print "log error: logarithm of zero; negative infinity\n"; return l(0)} if(x==1)return 0; if(base==0){print "log error: zero-based logarithm\n"; return 0 } if(base==1){print "log error: one-based logarithm; positive infinity\n";return -l(0)} scale+=6 if((-1<base&&base<0)||(0<base&&base<1)){x=-log(1/base,x);scale-=6;return x/1} if((-1<x && x<0)||(0<x && x<1)){x=-log(base,1/x);scale-=6;return x/1} if(base<0){ sx=1;if(x<0){x=-x;sx=-1} l=log(-base,x) dn=id_frac2_(l) os=scale;scale=0;dnm2=dn%2;scale=os if(dnm2&&dn*sx<0){scale-=6;return l/1} print "log error: -ve base: " if(dnm2)print "wrong sign for " print "implied " if(dnm2)print "odd root/integer power\n" if(!dnm2){ if(dn!=-2)print "even root\n" if(dn==-2)print "irrational power\n" } scale-=6;return 0; } if(x<0){ print "log error: +ve base: logarithm of a negative number\n" scale-=6;return 0; } x=ln(x)/ln(base);scale-=6;return x/1 } # Integer-only logarithm of x in given base # (compare digits function in digits.bc) define int_log(base,x) { auto os,p,c; if(0<x&&x<1) {return -int_log(base,1/x)} os=scale;scale=0;base/=1;x/=1 if(base<2)base=ibase; if(x==0) {scale=os;return 1-base*A^os} if(x<base) {scale=os;return 0 } c=length(x) # cheat and use what bc knows about decimal length if(base==A){scale=os;return c-1} if(base<A){if(x>A){c*=int_log(base,A);c-=2*(base<4)}else{c=0}}else{c/=length(base)+1} p=base^c;while(p<=x){.=c++;p*=base} scale=os;return(c-1) } # Lambert's W function 0 branch; Numerically solves w*e(w) = x for w # * is slow to converge near -1/e at high scales define lambertw0(x) { auto oib, a, b, w, ow, lx, ew, e1, eps; if(x==0) return 0; oib=ibase;ibase=A ew = -e(-1) if (x<ew) { print "lambertw0: expected argument in range [-1/e,oo)\n" ibase=oib return -1 } if (x==ew) {ibase=oib;return -1} # First approximation from : # http://www.desy.de/~t00fri/qcdins/texhtml/lambertw/ # (A. Ringwald and F. Schrempp) # via Wikipedia if(x < 0){ w = x/ew } else if(x < 500){ lx=l(x+1);w=0.665*(1+0.0195*lx)*lx+0.04 } else if((lx=length(x)-scale(x))>5000) { lx*=l(A);w=lx-(1-1/lx)*l(lx) } else { lx=l(x);w=l(x-4)-(1-1/lx)*l(lx) } # Iteration adapted from code found on Wikipedia # apparently by an anonymous user at 147.142.207.26 # and later another at 87.68.32.52 ow = 0 eps = A^-scale scale += 5 e1 = e(1) while(abs(ow-w)>eps&&w>-1){ ow = w if(x>0){ew=pow(e1,w)}else{ew=e(w)} a = w*ew b = a+ew a -= x; if(a==0)break b = b/a - 1 + 1/(w+1) w -= 1/b if(x<-0.367)w-=eps } scale -= 5 ibase=oib return w/1 } # Lambert's W function -1 branch; Numerically solves w*e(w) = x for w # * is slow to converge near -1/e at high scales define lambertw_1(x) { auto oib,os,oow,ow,w,ew,eps,d,iters; oib=ibase;ibase=A ew = -e(-1) if(ew>x||x>=0) { print "lambertw_1: expected argument in [-1/e,0)\n" ibase=oib if(x==0)return 1-A^scale if(x>0)return 0 return -1 } if(x==ew) return -1; os=scale eps=A^-os scale+=3 oow=ow=0 w=x w=l(-w) w-=l(-w) w+=sqrt(eps) iters=0 while(abs(ow-w)>eps){ oow=ow;ow=w if(w==-1)break w=(x*e(-w)+w*w)/(w+1) if(iters++==A+A||oow==w){iters=0;w-=A^-scale;scale+=2} } scale=os;ibase=oib return w/1 } # LambertW wrapper; takes most useful branch based on x # to pick a branch manually, use lambertw_1 or lambertw0 directly define w(x) { if(x<0)return lambertw_1(x) return lambertw0(x) } # Faster calculation of lambertw0(exp(x)) # . avoids large intermediate value and associated slowness # . numerically solves x = y+ln(y) for y define lambertw0_exp(x) { auto oy,y,eps; # Actual calculation is faster for x < 160 or thereabouts if(x<C*D)return lambertw0(e(x)); oy=0;y=l(x);y=x-y+y/x;eps=A^-scale while(abs(oy-y)>eps)y=x-l(oy=y) return y } # Shorthand alias for the above define w_e(x){ return lambertw0_exp(x) } # Numerically solve pow(y,y) = x for y define powroot(x) { auto r; if(x==0) { print "powroot error: attempt to solve for zero\n" return 0 } if(x==1||x==-1) {return x} if(x<=r=e(-e(-1))){ print "powroot error: unimplemented for values\n <0";r return 0 } r = ln(x) r /= w(r) return r } ## Triangular numbers # xth triangular number define tri(x) { auto xx x=x*(x+1)/2;xx=int(x) if(x==xx)return(xx) return(x) } # 'triangular root' of x define trirt(x) { auto xx x=(sqrt(1+8*x)-1)/2;xx=int(x) if(x==xx)x=xx return(x) } # Workhorse for following 2 functions define tri_step_(t,s) { auto tt t=t+(1+s*sqrt(1+8*t))/2;tt=int(t) if(tt==t)return(tt) return(t) } # Turn tri(x) into tri(x+1) without knowing x define tri_succ(t) { return(tri_step_(t,0+1)) } # Turn tri(x) into tri(x-1) without knowing x define tri_pred(t) { return(tri_step_(t,0-1)) } ## Polygonal Numbers # the xth s-gonal number: # e.g. poly(3, 4) = tri(4) = 1+2+3+4 = 10; poly(4, x) = x*x, etc define poly(s, x) { auto xx x*=(s/2-1)*(x-1)+1;xx=int(x);if(x==xx)x=xx return x } # inverse of the above = polygonal root: # e.g. inverse_poly(3,x)=trirt(x); inverse_poly(4,x)=sqrt(x), etc define inverse_poly(s, r) { auto t,xx t=(s-=2)-2 r=(sqrt(8*s*r+t*t)+t)/s/2;xx=int(r);if(r==xx)r=xx return r } # converse of poly(); solves poly(s,x)=r for s # i.e. if the xth polygonal number is r, how many sides has the polygon? # e.g. if the 5th polygonal number is 15, converse_poly(5,15) = 3 # so the polygon must have 3 sides! (15 is the 5th triangular number) define converse_poly(x,r) { auto xx x=2*((r/x-1)/(x-1)+1);xx=int(x);if(x==xx)x=xx return x } ## Tetrahedral numbers # nth tetrahedral number define tet(n) { return n*(n+1)*(n+2)/6 } # tetrahedral root = inverse of the above define tetrt(t) { auto k,c3,w; if(t==0)return 0 if(t<0)return -2-tetrt(-t) k=3^5*t*t-1 if(k<0){print "tetrt: unimplemented for 0<|t|<sqrt(3^-5)\n"; return 0} c3=cbrt(3) k=cbrt(sqrt(3*k)+3^3*t) return k/c3^2+1/(c3*k)-1 } ## Arithmetic-Geometric mean define arigeomean(a,b) { auto c,s; if(a==b)return a; s=1;if(a<0&&b<0){s=-1;a=-a;b=-b} if(a<0||b<0){print "arigeomean: mismatched signs\n";return 0} while(a!=b){c=(a+b)/2;a=sqrt(a*b);b=c} return s*a } # solve n = arigeomean(x,y) define inv_arigeomean(n, y){ auto ns,ox,x,b,c,d,i,s,eps; if(n==y)return n; s=1;if(n<0&&y<0){s=-1;n=-n;y=-y} if(n<0||y<0){print "inv_arigeomean: mismatched signs\n";return 0} if(n<y){x=y;y=n;n=x} n/=y scale+=2;eps=A^-scale;scale+=4 ns=scale x=n*(1+ln(n));ox=-1 for(i=0;i<A;i++){ # try to force quadratic convergence if(abs(x-ox)<eps){i=-1;break} ox=x;scale+=scale b=x+x/n*(n-arigeomean(1,x)); c=b+b/n*(n-arigeomean(1,b)); d=b+b-c-x if(d){x=(b*b-c*x)/d}else{x=b;i=-1;break} scale=ns } if(i!=-1){ # give up and converge linearly x=(x+ox)/2 while(abs(x-ox)>eps){ox=x;x+=x/n*(n-arigeomean(1,x))} } x+=5*eps scale-=6;return x*y/s }
Mantive o script original, mas recomendo que substitua a primeira linha por
#!/usr/bin/env bc -l
Isso vai evitar que o shell se perca e não encontre o bc no caminho certo!
Para utilizá-lo, salve com um nome qualquer, como funcs.bc
, torne-o executável com chmod +x
e rode como ./funcs.bc
. Escolha uma das funções do script e preencha com os números, como a raiz cúbica de 27, do exemplo abaixo. Digite quit
para sair do modo interativo do bc
.
./funcs.bc bc 1.06 Copyright 1991-1994, 1997, 1998, 2000 Free Software Foundation, Inc. This is free software with ABSOLUTELY NO WARRANTY. For details type `warranty'. root(27,3) 3.00000000000000000000000000000000000000000000000000 quit
Configurar .bcrc
Para carregar automaticamente as suas funções preferidas, crie um arquivo em ~/.bcrc
contendo todas elas. Uma boa sugestão para iniciar o seu .bcrc
está em https://github.com/idealvin/bc/blob/master/bcrc
pi=4*a(1); e=e(1); define sin(x) { if (x == pi/2) { return 1; } return s(x); } define cos(x) { if (x == pi/2) { return 0; } return c(x); } define tan(x) { if (x == pi/4) { return 1; } if (x == -pi/4) { return -1; } return s(x)/c(x); } define cot(x) { if (x == pi/4) { return 1; } if (x == -pi/4) { return -1; } return c(x)/s(x); } define sec(x) { return 1/cos(x); } define csc(x) { return 1/sin(x); } define asin(x) { if (x == 1) { return pi/2; } if (x == -1) { return -pi/2; } return a(x/sqrt(1-x^2)); } define arcsin(x) { return asin(x); } define acos(x) { if (x == 0) { return pi/2; } if (x == 1) { return 0; } if (x == -1) { return pi/1; } if (x > 0) { return a(sqrt(1-x^2)/x); } return pi/1 - acos(-x); } define arccos(x) { return acos(x); } define atan(x) { if (x == 1) { return pi/4; } if (x == -1) { return -pi/4; } return a(x); } define arctan(x) { return a(x); } define acot(x) { return pi/2-atan(x); } define arccot(x) { return acot(x); } define asec(x) { if (x >= 1) { return a(sqrt(x^2-1)); } return pi/1 - a(sqrt(x^2-1)); } define arcsec(x) { return asec(x); } define acsc(x) { if (x == 1) { return pi/2; } if (x == -1) { return -pi/2; } if (x > 1) { return a(1/sqrt(x^2-1)); } return -a(1/sqrt(x^2-1)); } define arccsc(x) { return acsc(x); } define ln(x) { return l(x); } define log(a, b) { return l(b)/l(a); } define lg(x) { return log(10, x); } define log10(x) { return log(10, x); } define log2(x) { return log(2, x); } define pow(a, b) { if (scale(b) == 0) { return a ^ b; } return e(b*l(a)); } define exp(x) { return e(x); } define cbrt(x) { return pow(x, 1/3); } define abs(x) { if (x < 0) { return -x; } return x; } define bessel(n, x) { return j(n,x); } define a(m, n) { if (n < 0) { return 0; } v = 1; for (i = 0; i < n; i++) { v *= (m - i); } return v; } define fac(n) { return a(n, n); } define c(m, n) { auto v if (n < 0) { return 0; } s = scale; scale = 0; v = a(m, n) / a(n, n); scale = s; return v; } define rad(deg) { return deg/180*pi; } define deg(rad) { return rad/pi*180; }
Depois, insira o caminho do .bcrc
no seu ~/.bashrc
. Utilize a variável BC_ENV_ARGS
que é carregada pelo bc
toda vez que ele inicia. Também sugiro a opção -l
, que carrega a biblioteca matemática padrão do bc
.
export BC_ENV_ARGS="-l $HOME/.bcrc"
E por hora isso é tudo. Esse e muitos outros scripts com funções incríveis estão no site do phodd.net. Recomendo visitar os seguintes links:
E mais funções interessantes para inspirar idéias:
- http://x-bc.sourceforge.net/extensions_bc.html
- http://x-bc.sourceforge.net/scientific_constants_bc.html
E, não menos importante, no manual do bc tem outras informações muito importantes para dominar esta ferramenta.
man bc
Até a próxima!
Uma resposta
Sensacional! Adoro o detalhamento dos posts!