Libraries for bc and dc.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

#### 337 lines 10 KiB Raw Permalink Blame History

 `#!/usr/local/bin/bc -l funcs.bc` `### Interest.BC - Compound interest, loan amortisation and compound savings` `# requires funcs.bc for pow, root, lambertw*` `## Conventions in this library` `#* ic = initial capital` `#* rate = interest rate in form 1+fraction where 0=percent||percent>=100){` ` print "warning: given percentage is outside ]0..100[\n";` ` }` ` return 1+percent/100;` `}` `define fraction_to_rate(fraction) {` ` if(0>=percent||percent>=100){` ` print "warning: given fraction is outside ]0..1[\n";` ` }` ` return 1+fraction;` `}` `define rate_to_fraction(rate) {` ` if(1>=rate||rate>=2){` ` print "warning: given rate is outside ]1..2[\n";` ` }` ` return rate-1;` `}` `define rate_to_percentage(rate) {` ` return rate_to_fraction(rate)*100;` `}` `### Compound Interest` `# Parameters always given in order:` `# (fc, ic, rate, nt)` `# although one or more will be missing` `# Find final capital from initial at given rate and number of terms` `define compound_fc(ic,rate,nt){` ` return ic*pow(rate,nt)` `}` `# Find initial capital from final at given rate and number of terms` `define compound_ic_from_fc(fc,rate,nt){` ` return fc/pow(rate,nt)` `}` `# Find number of terms given rate and final and initial capital` `define compound_nt_from_fc(fc,ic,rate){` ` return l(fc/ic)/l(rate)` `}` `# Find rate given number of terms and final and initial capital` `define compound_rate_from_fc(fc,ic,nt){` ` return root(fc/ic,nt)` `}` `### Loan Amortisation - Assume payment occurs immediately after interest is added` `# Parameters are always given in the order:` `# (*a__[], tpaym, paym, ic, rate, nt, spt)` `# although one or more will be missing` `# e.g. tpaym and paym never happen together` `#` `# N.B. ic/fc occur AFTER tpaym/paym here` `## Basic Calculations` `# Determine payment; +Interest-Payment, Once per term` `define loan_paym(ic,rate,nt) {` ` auto rn;` ` rn = pow(rate, nt)` ` return ic*rn*(rate-1)/(rn-1)` `}` `# Total payment over all terms based on interest and payment once per term` `define loan_tpaym(ic,rate,nt) {` ` auto rn;` ` rn = pow(rate, nt)` ` return nt*ic*rn*(rate-1)/(rn-1)` `}` `# Determine payment; +Interest-Payment, Multiple times per term` `define loan_paym_split(ic,rate,nt,spt) {` ` return loan_paym(ic,root(rate,spt),nt*spt)` `}` `# Total payment over all terms based on interest and payment multiple times per term` `define loan_tpaym_split(ic,rate,nt,spt) {` ` return loan_tpaym(ic,root(rate,spt),nt*spt)` `}` `# Generate an array of owed capital at each term` `define loan_apaym(*a__[],ic,rate,nt){` ` auto i,paym;` ` paym = loan_paym(ic,rate,nt);` ` a__[0]=ic;for(i=1;i<=nt;i++)a__[i]=a__[i-1]*rate-paym;` ` a__[i]=0;` ` return nt;` `}` `# Generate an array of owed capital at each subterm` `define loan_apaym_split(*a__[],ic,rate,nt,spt) {` ` auto i,paym;` ` rate = root(rate, spt)` ` nt *= spt;` ` paym = loan_paym(ic,rate,nt);` ` a__[0]=ic;for(i=1;i<=nt;i++)a__[i]=a__[i-1]*rate-paym;` ` a__[i]=0;` ` return nt;` `}` `## Reverse calculations` `# Given the once-per-term payment, find the initial capital` `define loan_ic_from_paym(paym,rate,nt) {` ` auto rn;` ` rn = pow(rate, nt)` ` return paym*(rn-1)/((rate-1)*rn)` `}` `# Given the total of all once-per-term payments, find the initial capital` `define loan_ic_from_tpaym(tpaym,rate,nt) {` ` auto rn;` ` rn = pow(rate, nt)` ` return tpaym*(rn-1)/((rate-1)*rn*nt)` `}` `# Given the multiple-per-term payment, find the initial capital` `define loan_ic_from_paym_split(paym,rate,nt,spt) {` ` return loan_ic_from_paym(paym,root(rate,spt),nt*spt)` `}` `# Given the total of all multiple-per-term payments, find the initial capital` `define loan_ic_from_tpaym_split(tpaym,rate,nt,spt) {` ` return loan_ic_from_tpaym(tpaym,root(rate,spt),nt*spt)` `}` `# Given the once-per-term payment, find the interest rate` `define loan_rate_from_paym(paym,ic,nt){` ` auto os,i,k,rate,ratf,ratg,ratd;` ` if(paym*nt==ic)return 1/1;` ` k=paym/ic;` ` rate=root(k*nt,nt/2); # good initial guess` ` os=scale;scale+=scale` ` for(i=scale;i>1;i/=2){` ` # use of rat plus d, (e,) f, and g is a deliberate pun on 'rate'` ` ratf=1+k*(1-pow(rate,-nt));# f and g are iterated approximants` ` ratg=1+k*(1-pow(ratf,-nt));` ` ratd=(ratf+ratf-rate-ratg);# d is a divisor that could end up as 0` ` if(ratd==0){rate=1;break} # so escape if that happens` ` rate=(ratf*ratf-rate*ratg)/ratd;# glai(rate,ratf,ratg)` ` # this trick causes the iteration to converge exponentially rather` ` # than geometrically as found by repeating ratf=...;rate=ratf` ` }` ` scale=os;return rate/1` `}` `# Given the total of all once-per-term payments, find the interest rate` `define loan_rate_from_tpaym(tpaym,ic,nt) {` ` return loan_rate_from_paym(tpaym/nt,ic,nt);` `}` `# Given the multiple-per-term payment, find the interest rate` `define loan_rate_from_paym_split(paym,ic,nt,spt) {` ` return pow(loan_rate_from_paym(paym,ic,nt*spt),spt);` `}` `# Given the total of all multiple-per-term payments, find the interest rate` `define loan_rate_from_tpaym_split(tpaym,ic,nt,spt) {` ` return pow(loan_rate_from_tpaym(tpaym,ic,nt*spt),spt);` `}` `# Given the once-per-term payment, find the number of terms` `define loan_nt_from_paym(paym,ic,rate) {` ` auto d;` ` d=paym-ic*(rate-1);` ` return l(paym/d)/l(rate)` `}` `# Given the total of all once-per-term payments, find the number of terms` `define loan_nt_from_tpaym(tpaym,ic,rate) {` ` auto q,l;` ` q = tpaym/(ic*(rate-1));` ` l = l(rate);` ` return q + lambertw0(-q*l/pow(rate,q))/l` `}` `# Given the multiple-per-term payment, find the number of terms` `define loan_nt_from_paym_split(paym,ic,rate,spt) {` ` return loan_nt_from_paym(paym,ic,root(rate,spt))/spt` `}` `# Given the total of all multiple-per-term payments, find the number of terms` `define loan_nt_from_tpaym_split(tpaym,ic,rate,spt) {` ` return loan_nt_from_tpaym(tpaym,ic,root(rate,spt))/spt` `}` `# Given the payment, determine the number of subterms within the term` `define loan_spt_from_paym(paym,ic,rate,nt) {` ` auto rn;` ` rn = pow(rate, nt)` ` return l(rate)/l(1+paym*(rn-1)/(ic*rn)); ` `}` `# Given the total of all payments, determine the number of subterms within the term` `define loan_spt_from_tpaym(tpaym,ic,rate,nt) {` ` auto q,l,rn,temp;` ` rn = pow(rate, nt)` ` l = l(rate);` ` q = nt*ic*rn/(tpaym*(rn-1));` ` return -1/(q + lambertw_1(-q*l/pow(rate,q))/l);` `}` `### Savings - Assume interest is added before extra payment is added` `# Parameters here are always given in the order:` `# (*a__[], fc, ic, tpaym, paym, rate, nt, spt)` `# although one or more will be missing` `# e.g. ic and fc never happen together` `#` `# N.B. ic/fc occur BEFORE tpaym/paym here` `# Determine final captial savings given initial lump sum, regular payment,` `# . interest rate and number of terms (+Interest+Payment)` `define saving_fc(ic,paym,rate,nt){` ` auto rn;` ` rn = pow(rate,nt);` ` return ic*rn+paym*(rn-1)/(rate-1)` `}` `# As above but assumes terms are split into subterms` `define saving_fc_split(ic,paym,rate,nt,spt){` ` return saving_fc(ic,paym,root(rate,spt),nt*spt)` `}` `# Generate an array of current capital at each term` `define saving_afc(*a__[],ic,paym,rate,nt){` ` auto i;` ` a__[0]=ic;for(i=1;i<=nt;i++)a__[i]=a__[i-1]*rate+paym;` ` a__[i]=0;` ` return nt;` `}` `# Generate an array of current capital at each subterm` `define saving_afc_split(*a__[],ic,paym,rate,nt,spt) {` ` auto i;` ` rate = root(rate, spt);` ` nt *= spt;` ` #paym = loan_paym(ic,rate,nt);` ` a__[0]=ic;for(i=1;i<=nt;i++)a__[i]=a__[i-1]*rate+paym;` ` a__[i]=0;` ` return nt;` `}` `## Reverse calculations - given final capital and all but one of the others,` `## determine the value of the missing parameter` `# Determine initial capital (savings starter lump sum) based on final capital` `define saving_ic_from_fc(fc,paym,rate,nt) {` ` auto rn;` ` rn = pow(rate,nt);` ` return (fc-paym*(rn-1)/(rate-1))/rn;` `}` `# as above only with specified number of subterms per term` `define saving_ic_from_fc_split(fc,paym,rate,nt,spt) {` ` return saving_ic_from_fc(fc,paym,root(rate,spt),nt*spt)` `}` `# Determine regular payment based on desired final capital and initial lump sum` `define saving_paym_from_fc(fc,ic,rate,nt) {` ` auto rn;` ` rn = pow(rate,nt);` ` return (fc-ic*rn)*(rate-1)/(rn-1)` `}` `# as above only with specified number of subterms per term` `define saving_paym_from_fc_split(fc,ic,rate,nt,spt){` ` return saving_paym_from_fc(fc,ic,root(rate,spt),nt*spt)` `}` `# Determine ideal interest rate for given initial and final conditions` `define saving_rate_from_fc(fc,ic,paym,nt) {` ` auto os,i,ratd,rate,ratf,ratg;` ` rate = root(fc/(ic+nt*paym),nt) # good initial guess` ` os=scale;scale+=scale` ` for(i=scale;i>1;i/=2){` ` ratf=root((fc*(rate-1)+paym)/(ic*(rate-1)+paym),nt)` ` ratg=root((fc*(ratf-1)+paym)/(ic*(ratf-1)+paym),nt)` ` ratd=(ratf+ratf-rate-ratg);# d is a divisor that could end up as 0` ` if(ratd==0){rate=1;break} # so escape if that happens` ` rate=(ratf*ratf-rate*ratg)/ratd;# glai(rate,ratf,ratg)` ` }` ` scale=os;return rate/1` `}` `# as above only with specified number of subterms per term` `define saving_rate_from_fc_split(fc,ic,paym,nt,spt) {` ` return pow(saving_rate_from_fc(fc,ic,paym,nt*spt),spt)` `}` `# Determine number of compounding terms required for desired final capital` `define saving_nt_from_fc(fc,ic,paym,rate){` ` return l( (fc*(rate-1)+paym)/(ic*(rate-1)+paym) )/l(rate)` `}` `# as above only with specified number of subterms per term` `define saving_nt_from_fc_split(fc,ic,paym,rate,spt) {` ` return saving_nt_from_fc(fc,ic,paym,root(rate,spt))/spt` `}` `# Determine number of subterms per term based on other details` `define saving_spt_from_fc(fc,ic,paym,rate,nt) {` ` auto rn;` ` rn = pow(rate,nt);` ` return l(rate)/l(1+paym*(rn-1)/(fc-ic*rn));` `}`