Sindbad~EG File Manager
/* binomialtheorem operator for MathXpert
Michael Beeson
Original date 11.21.90
modified 1.20.99
1.11.00 modified remove_zero_powers
7.20.05 made binomialtheorem and plainbinomialtheorem fail on exponent 0.
*/
#define ALGEBRA_DLL
#include <string.h>
#include <assert.h>
#include "globals.h"
#include "ops.h"
#include "trig.h"
#include "simpprod.h"
#include "pvalaux.h" /* for square2 */
#include "symbols.h"
#include "errbuf.h"
#include "autosimp.h" /* SetShowStepOperation */
#include "psubst.h"
static term remove_zero_powers(term t);
/*____________________________________________________________________*/
MEXPORT_ALGEBRA int cubeofsum(term t, term arg, term *next, char *reason)
/* (a+b)^3 = a^3 + 3a^2b + 3ab^2 + b^3 */
{ if(FUNCTOR(t) != '^')
return 1;
if(FUNCTOR(ARG(0,t)) != '+')
return 1;
if(!equals(ARG(1,t),three))
return 1;
return binomialtheorem(t,arg,next,reason);
/* it sets the reason correctly when it calls SetShowStepOperation */
}
/*____________________________________________________________________*/
MEXPORT_ALGEBRA int cubeofdif(term t, term arg, term *next, char *reason)
/* (a-b)^3 = a^3 - 3a^2b + 3ab^2 - b^3 */
{ term u;
if(FUNCTOR(t) != '^')
return 1;
u = ARG(0,t);
if(FUNCTOR(u) != '+')
return 1;
if(!NEGATIVE(ARG(ARITY(u)-1,u)))
return 1;
if(!equals(ARG(1,t),three))
return 1;
return binomialtheorem(t,arg,next,reason);
}
/*____________________________________________________________________*/
MEXPORT_ALGEBRA int binomialtheorem(term t, term arg, term *next, char *reason)
/* expand a power by the binomial theorem */
/* use sigma notation for powers more than 4, but write them
out directly for powers 2, 3 and 4. Also write them out directly
for powers up to 8 when doing integrals.
*/
{ term u,n,a,b,index,v;
unsigned long k; /* the exponent */
int sign = 1;
if(FUNCTOR(t) != '^')
return 1;
u = ARG(0,t);
n = ARG(1,t);
if(FUNCTOR(u) != '+')
return 1;
if(ARITY(u) > 2) /* (a+b+c)� */
{ a = u;
SETFUNCTOR(a,'+',(unsigned short)(ARITY(u)-1));
b = ARG(ARITY(u)-1,u);
v = make_term('+',2);
ARGREP(v,0,a);
ARGREP(v,1,b); /* v = sum(a,b) will flatten the sum again uselessly */
return binomialtheorem(make_power(v,n),arg,next,reason);
}
if(OBJECT(n) && TYPE(n)==BIGNUM)
{ errbuf(0, english(426));
/* Sorry, the exponent has to be less than two billion. */
return 1;
}
if(! ISINTEGER(n))
{ errbuf(0, english(976));
/* Exponent must be an integer */
return 1; /* can only handle integer exponent */
}
k = INTDATA(n);
a = ARG(0,u);
b = ARG(1,u);
if(NEGATIVE(b))
{ sign = -1;
b = ARG(0,b);
}
if(k == 0)
return 1;
if(k <= 5)
/* don't change the 5 unless you soup up smallbinomial to handle it */
{ smallbinomial(t,next);
strcpy(reason, k == 2 ? "(a+b)^2 = a^2+2ab+b^2" : english(427)); /* binomial theorem */
switch(k)
{ case 2:
if(sign == 1)
{ strcpy(reason,"(a+b)^2=a^2+2ab+b^2");
SetShowStepOperation(squareofsum);
}
else
{ strcpy(reason,"(a-b)^2=a^2+2ab+b^2");
SetShowStepOperation(squareofdif);
}
break;
case 3:
if(sign == 1)
{ strcpy(reason,"(a+b)^3=a^3+3a^2b+3ab^2+b^3");
SetShowStepOperation(cubeofsum);
}
else
{ strcpy(reason,"(a-b)^3=a^3-3a^2b+3ab^2-b^3");
SetShowStepOperation(cubeofdif);
}
break;
case 4: /* fall through */
case 5:
SetShowStepOperation(plainbinomialtheorem);
break;
}
return 0;
}
/* Now k > 4, so use binomial coefficients */
*next = make_term(SUM,4);
index = index_variable(t);
if(ONE(a))
u = product(make_binomial(n,index),make_power(b,index));
else if ONE(b)
u = product(make_binomial(n,index),make_power(a,sum(n,tnegate(index))));
else
{ u = make_term('*',3);
ARGREP(u,1,make_power(a,sum(n,tnegate(index)))); /* a^(n-i) */
ARGREP(u,2,make_power(b,index)); /* b^i */
ARGREP(u,0,make_binomial(n,index));
}
if(sign == -1)
u = product(make_power(minusone,index),u);
ARGREP(*next,0,u);
ARGREP(*next,3,n);
ARGREP(*next,2,zero);
ARGREP(*next,1,index);
HIGHLIGHT(*next);
strcpy(reason, english(427)); /* binomial theorem */
return 0;
}
/*______________________________________________________________*/
MEXPORT_ALGEBRA int plainbinomialtheorem(term t, term arg, term *next,char *reason)
/* expand t by the binomial theorem, without using sigma notation
and binomial coefficients, returning in *ans the standard polynomial
form of the answer. */
{ int i,err;
term a,b,d;
unsigned short k;
bignum c,w,q,r,z1,z2;
term u,temp;
long clong;
if(FUNCTOR(t) != '^' || FUNCTOR(ARG(0,t)) != '+')
return 1;
if(!INTEGERP(ARG(1,t)))
{ errbuf(0,english(976));
/* Exponent must be an integer */
return 1;
}
if(!ISINTEGER(ARG(1,t)) || INTDATA(ARG(1,t)) > 300)
{ if(ARITY(t) > 2)
{ if(INTDATA(ARG(1,t)) > 100)
{ errbuf(0, english(975));
/* Exponent is too large. */
return 1;
}
}
else /* if(ARITY(t) == 2) */
{ if(
(ONE(ARG(1,ARG(0,t))) && ISATOM(ARG(0,ARG(0,t)))) ||
(ONE(ARG(0,ARG(0,t))) && ISATOM(ARG(1,ARG(0,t))))
)
{ if(INTDATA(ARG(1,t)) > 800)
{ errbuf(0, english(975));
/* we can do (x+1)^800 but not (x+1)^850 as of January, 1999 */
return 1;
}
}
else
{ errbuf(0,english(975));
/* In all other cases 300 is the maximum exponent. */
return 1;
}
}
}
u = ARG(0,t);
k = (unsigned short) INTDATA(ARG(1,t));
if(k==0)
return 1;
if(ARITY(u) > 2) /* (a+b+c)� */
{ a = u;
if(get_mathmode() == AUTOMODE && INTDATA(ARG(1,t)) > 3)
return 1; /* expanding (a+b+c)^n leads to out-of-memory errors
all too easily. */
SETFUNCTOR(a,'+',(unsigned short)(ARITY(u)-1));
b = ARG(ARITY(u)-1,u);
temp = make_term('+',2);
ARGREP(temp,0,a);
ARGREP(temp,1,b);
return plainbinomialtheorem(make_power(temp,ARG(1,t)),arg,next,reason);
}
a = ARG(0,u);
b = ARG(1,u);
SET_ALREADY(a); /* so polyval won't go into them */
SET_ALREADY(b);
if(k < 5)
return binomialtheorem(t,arg,next,reason);
strcpy(reason, english(427)); /* binomial theorem */
/* for larger k we do not want to evaluate each binomial coefficient separately */
c = bigint(1L);
*next = make_term('+',(unsigned short)(k+1));
ARGREP(*next,0, ONE(a) ? one : make_power(a,make_int(k)));
ARGREP(*next,k, ONE(b) ? one : make_power(b,make_int(k)));
for(i=1;i<=(k+2)/2;i++)
{ z1 = bigint(k-i+1);
z2 = bigint(i);
bigmult(c, z1,&w);
bigdivide(w,z2,&q,&r);
if(r.ln!=1 || r.val[0] != 0)
assert(0);
freespace(w.val);
freespace(r.val);
freespace(z1.val);
freespace(z2.val);
c=q;
err = bignum_long(c,&clong);
if(!err)
d= make_int(clong);
else
d = make_bignum(c);
if(ONE(a))
ARGREP(*next,i,product(d,make_power(b,make_int(i))));
else if(ONE(b))
ARGREP(*next,i,product(d,make_power(a,make_int(k-i))));
else
ARGREP(*next,i,product3(d,make_power(a,make_int(k-i)),make_power(b,make_int(i))));
if(2*i == k+2)
break; /* this was the middle term (k is even, there are an odd number of terms) */
if(ONE(b))
ARGREP(*next,k-i,product(d,make_power(a,make_int(i))));
else if(ONE(a))
ARGREP(*next,k-i,product(d,make_power(b,make_int(k-i))));
else
ARGREP(*next,k-i,product3(d,make_power(a,make_int(i)),make_power(b,make_int(k-i))));
}
HIGHLIGHT(*next);
return 0;
}
/*________________________________________________________________________*/
MEXPORT_ALGEBRA int sigmatosum(term t, term arg, term *next, char *reason)
/* expand indexed sum to actual sum */
/* Difference of the limits must be an integer */
{ term u,l,dif,summand,index,w,temp;
unsigned short n;
int i;
if(FUNCTOR(t) != SUM)
return 1;
u = ARG(3,t);
l = ARG(2,t);
polyval(sum(u,tnegate(l)),&dif);
if(NEGATIVE(dif))
{ if(!INTEGERP(ARG(0,dif)))
{ errbuf(0, english(817));
/* Difference of upper and lower limit must be an integer */
return 1;
}
*next = zero;
return 0;
}
if(!ISINTEGER(dif))
{ errbuf(0,english(817));
/* Difference of upper and lower limit must be an integer */
return 1;
}
if(INTDATA(dif) > 100)
{ errbuf(0, english(819)); /* Too many terms */
return 1;
}
strcpy(reason, english(820)); /* definition of � */
n = (unsigned short ) (INTDATA(dif) + 1); /* number of terms in the sum */
if(n==1)
{ psubst(l,ARG(1,t),ARG(0,t),next);
HIGHLIGHT(*next);
return 0;
}
summand = ARG(0,t);
index = ARG(1,t);
*next = make_term('+',n);
for(i=0;i<n;i++)
{ polyval(sum(make_int(i),l),&w);
subst(w,index,summand,&temp);
value(temp,&u);
ARGREP(*next,i,remove_zero_powers(u));
}
HIGHLIGHT(*next);
return 0;
}
/*________________________________________________________________________*/
static term remove_zero_powers(term t)
/* apply the laws a^0 = 1 and a^1 = a throughout t, and then the law 1*a = a */
/* when expanding sigma notation we don't want zero exponents, which
are undefined when the base is zero. Thus sum(x^i,i,0,2) = 1+x+x^2
IS INDEED defined when x = 0 */
/* also returns e.g. -2x^3 on (-2)x^3 */
{ unsigned short n=ARITY(t);
unsigned short f = FUNCTOR(t);
unsigned short k;
int i;
term u,ans;
if(ATOMIC(t))
return t;
if(f== '^' && ZERO(ARG(1,t)))
return one;
if(f=='^' && ONE(ARG(1,t)))
return ARG(0,t);
ans = make_term(f,n);
if(f == '*')
{ k = 0;
for(i=0;i<n;i++)
{ u = remove_zero_powers(ARG(i,t));
if(ZERO(u))
return zero;
if(!ONE(u))
{ ARGREP(ans,k,u);
k++;
}
}
if(k==0)
{ RELEASE(ans);
return one;
}
if(k==1)
{ u = ARG(0,ans);
RELEASE(ans);
return u;
}
SETFUNCTOR(ans,'*',k);
if(NEGATIVE(ARG(0,ans)))
{ ARGREP(ans,0,ARG(0,ARG(0,ans)));
return tnegate(ans); /* return -2x^3 instead of (-2)x^3 */
}
return ans;
}
for(i=0;i<n;i++)
ARGREP(ans,i,remove_zero_powers(ARG(i,t)));
return ans;
}
Sindbad File Manager Version 1.0, Coded By Sindbad EG ~ The Terrorists