Sindbad~EG File Manager
/*
M. Beeson; trig simplification strategies for Mathpert
1.8.91 original date
6.28.99 modified
1.4.00 added itanh and icoth
1.15.00 added conditions to get sinhalf1, coshalf1, triplesin, triplecos, used on
appropriate numerical multiples of pi
2.3.00 added conditions to get sinsum, sindif, cossum, cosdif used on complex arguments
11.21.00 modified conditions for sinsum, cossum, tansum to handle e.g. cos(deg(60)-deg(45))
*/
#define AUTOMODE_DLL
#include <assert.h>
#include <math.h> /* fabs, used in ISZERO */
#include <string.h>
#include "globals.h"
#include "graphstr.h"
#include "display.h"
#include "document.h"
#include "tdefn.h"
#include "checkarg.h" /* for operator typedef */
#include "ops.h" /* for prototypes of operators */
#include "operator.h"
#include "trig.h"
#include "calc.h"
#include "probtype.h" /* set_control_flags needs values of problemtype */
#include "prover.h"
#include "polynoms.h"
#include "exec.h"
#include "algaux.h"
#include "order.h"
#include "automode.h"
#include "symbols.h"
#include "cflags.h"
#include "autosimp.h"
#include "pvalaux.h" /* content_factor */
#include "autosum.h" /* contains_arctrigs */
#include "autotrig.h"
#include "deval.h"
static int stop_trigexpand(void);
static int ispoweroftwo(term t);
/*______________________________________________________________________*/
static int sincosflag;
void set_sincosflag(int n)
{ sincosflag = n;
}
/*_______________________________________________________________*/
void autotrig(term t,actualop *o, int *nops)
/* post_ops for the case of a term t with a trig or arctrig functor */
{ unsigned short f = FUNCTOR(t);
unsigned short localtrigflag=0;
int trigexpandflag = get_trigexpandflag();
term u;
unsigned short g,h;
int topic = get_currenttopic();
int problemtype = get_problemtype();
int intflag = get_intflag();
int i=0;
unsigned short const *path = get_path();
int pathlength = get_pathlength();
u = ARG(0,t);
g = FUNCTOR(u);
if(NOTDEFINED(u))
{ switch(f)
{ case ATAN:
o[i] = ataninfinity; ++i;
break;
case ASEC:
o[i] = asecinfinity; ++i;
break;
case ACSC:
o[i] = acscinfinity; ++i;
break;
case ACOT:
o[i] = acotinfinity; ++i;
o[i] = acotminusinfinity; ++i;
break;
default:
o[i] = triginfinity; ++i;
break;
}
*nops = i;
return;
}
if(OBJECT(u) && TYPE(u) == DOUBLE)
{ o[i] = devalop; ++i;
*nops = i;
return;
}
if(TRIGFUNCTOR(f))
{ if(g=='+' &&
( topic != _trig_addition || get_currentline() > 0)
)
/* we want sin(x+2�) = sin x proved by sum identities under
topic _trig_addition, not just assumed; but we
need to use sin(2�) = 0 in the proof. */
{ switch(f)
{ case SIN:
o[i] = sinperiodic; ++i;
break;
case COS:
o[i] = cosperiodic; ++i;
break;
case TAN:
o[i] = tanperiodic; ++i;
break;
case SEC:
o[i] = secperiodic; ++i;
break;
case CSC:
o[i] = cscperiodic; ++i;
break;
case COT:
o[i] = cotperiodic; ++i;
break;
}
}
if( g == '*' || ZERO(u) || equals(u,pi) )
{ switch(f)
{ case SIN:
o[i] = zeroesofsin; ++i;
break;
case COS:
o[i] = onesofcos; ++i;
break;
case TAN:
o[i] = zeroesoftan; ++i;
break;
}
}
if(ISZERO(u) || (FUNCTOR(u) == DEG && ISZERO(ARG(0,u))))
{ switch(f)
{ case SIN:
o[i] = sin0; ++i;
break;
case COS:
o[i] = cos0; ++i;
break;
case TAN:
o[i] = tan0; ++i;
break;
}
}
if(contains(u,PI_ATOM) || seminumerical(u))
{ o[i] = (g==DEG ? mod360 : mod2pi); ++i;
/* You need this for sin(x+k�), observe x+k� isn't seminumerical */
}
if(seminumerical(u))
{ /* evaluate trig functions */
switch(f)
{ case SIN:
o[i] = zeroesofsin; ++i;
break;
case COS:
o[i] = onesofcos; ++i;
break;
case TAN:
o[i] = zeroesoftan; ++i;
break;
}
o[i] = sin90; ++i;
o[i] = sin30; ++i;
o[i] = sin45; ++i;
if(g == DEG && ISINTEGER(ARG(0,u)) && (INTDATA(ARG(0,u)) % 15 == 0))
{ o[i] = combine3045; ++i;
}
}
}
switch(f)
{ case ATAN:
if(g == '-')
{ o[i] = arctanodd; ++i;
}
o[i] = evalarctan; ++i;
if(g == TAN)
{ o[i] = atantan; ++i;
}
break;
case ACOS:
if(g == '-')
{ o[i] = arccosodd; ++i;
}
o[i] = evalarccos; ++i;
break;
case ASIN:
if(g == '-')
{ o[i] = arcsinodd; ++i;
}
o[i] = evalarcsin; ++i;
break;
case ACOT:
if(!intflag)
{ o[i] = evalarccot; ++i;
}
break;
case ACSC:
if(!intflag)
{ o[i] = evalarccsc; ++i;
}
break;
case ASEC:
if(!intflag)
{ o[i] = evalarcsec; ++i;
}
break;
case SEC:
if(g=='-')
{ o[i] = seceven; ++i;
break;
}
if(g=='+')
{ o[i] = seccomplement; ++i;
}
if(ARCTRIGFUNCTOR(g) || iscomplex(u))
{ o[i] = secrule; ++i;
}
if( (!(trigexpandflag & 0x10) || (trigexpandflag & 0x01)) &&
/* don't use secrule if only tan and sec occur (0x10)
unless not all args are the same (0x01), in which
case go ahead and use it, e.g. when sec 2x
and sec x both occur */
limfractflag != -1 && /* in a limit of fractions */
(pathlength < 3 || !TRIGFUNCTOR(path[pathlength-3])) &&
!(pathlength >= 3 && path[pathlength-3] == '^')
/* sec� will be handled in autoexp one level up */
/* so if you change these conditions change those too */
/* see comments near tanrule */
)
{ o[i] = secrule; ++i; /* may be inhibited if inside a sum
containing only sec and tan */
}
else if(limfractflag == -1 && /* in a limit of fractions */
pathlength >= 3 &&
path[pathlength-3] == '*'
/* a factor of a product in a fraction in a limit */
)
{ o[i] = secrule; ++i;
}
else if(limitflag && get_whichpass() > 0)
{ o[i] = secrule; ++i;
}
else if(SOLVETYPE(problemtype) &&
(trigexpandflag & 0x02)
)
/* SEC is the ONLY trig function in the problem;
bit 0x02 set says there's only one trig function,
and it must be SEC or we wouldn't be here.
Without this we can't solve x = sec a */
{ o[i] = secrule; ++i;
}
switch(g)
{ case ATAN:
o[i] = secatan; ++i;
break;
case ACOS:
o[i] = secacos; ++i;
break;
case ASIN:
o[i] = secasin; ++i;
break;
}
break;
case CSC:
if(g=='-')
{ o[i] = cscodd; ++i;
break;
}
if(g=='+')
{ o[i] = csccomplement; ++i;
}
if(ARCTRIGFUNCTOR(g) || iscomplex(u))
{ o[i] = cscrule; ++i;
}
if( (!(trigexpandflag & 0x100) || (trigexpandflag & 0x01)) &&
limfractflag != -1 &&
(pathlength < 3 || !TRIGFUNCTOR(path[pathlength-3])) &&
/* see comments near tanrule */
!(pathlength >= 3 && path[pathlength-3] == '^')
/* see comments at the other 'pathlength-3' */
)
{ o[i] = cscrule; ++i; /* may be inhibited inside a sum
containing only csc and cot */
}
else if(limfractflag == -1 && /* in a limit of fractions */
pathlength >= 3 &&
path[pathlength-2] == '*'
/* a factor of a product in a fraction in a limit */
)
{ o[i] = cscrule; ++i;
}
else if(limitflag && get_whichpass() > 0)
{ o[i] = cscrule; ++i;
}
else if( SOLVETYPE(problemtype ) &&
(trigexpandflag & 0x02) /* CSC is the ONLY trig function */
)
{ o[i] = cscrule; ++i;
}
break;
case COT:
if(pathlength > 1 && path[pathlength-2] == ATAN)
{ /* simplify arctan(cot x) => arctan(tan(pi/2-x)) */
o[i] = cottotan2; ++i;
}
if(g=='-')
{ o[i] = cotodd; ++i;
break;
}
if(iscomplex(u) || contains_complexvar(u))
{ o[i] = icoth; ++i;
break;
}
if(ARCTRIGFUNCTOR(g))
/* simplify cot(arcsin x) = 1/tan(arcsin x) */
{ o[i] = cottotan; ++i;
}
if(g=='+')
{ o[i] = cotcomplement; ++i;
}
/* if only COT and TAN occur, rewrite cot as 1/tan */
/* example: 1 - cot^2 x
���������� = cot^2 x
tan^2 x - 1
which is solved easily using cot => 1/tan but
leads to loops if everything is rewritten in sin
and cos.
*/
if(g == '/' &&
((trigexpandflag & 1) || topic == _half_angle)
)
{ o[i] = cothalf1; ++i;
o[i] = cothalf2; ++i; /* used if cothalf1 is inhibited */
}
if(pathlength >= 3 && path[pathlength-3] == '^')
/* this is in the base of an exponent--postpone
action till postops handles the exponent.
If path[pathlength-3] is '^' then path[pathlength-2]
is 1 or 0 according as we are in denom or num,
that's why we have 3 here.
cot� will be handled one level up in autoexp,
so if you change these conditions change those too. */
break;
if(iscomplex(u))
{ o[i] = cottosincos; ++i;
}
else if((trigexpandflag & 0x0004) && /* only cot and tan */
!difflag && /* don't get rid of cot when differentiating */
g != '+' /* don't preempt cotsum */
)
{ o[i] = cottotan; ++i;
o[i] = cottosincos; ++i;
/* e.g. on equation cot x = 0, cottotan can't be applied
because its side condition cot x != 0 can't be inferred. */
break;
}
else if(limfractflag == -1 && /* in a limit of fractions */
pathlength >= 3 &&
path[pathlength-3] == '*'
/* a factor of a product in a fraction in a limit */
)
{ o[i] = cottotan; ++i;
}
else if(limitflag && get_whichpass() > 0)
{ o[i] = cottosincos; ++i;
}
else if(SOLVETYPE(problemtype) &&
(trigexpandflag & 0x02)
)
{ o[i] = cottotan; ++i;
o[i] = cottosincos; ++i;
/* e.g. on equation cot x = 0, cottotan can't be applied
because its side condition cot x != 0 can't be inferred. */
}
if(!(trigexpandflag & 0x100) && limfractflag != -1 &&
!difflag && g != '+' &&
(pathlength < 3 || !TRIGFUNCTOR(path[pathlength-3]))
/* see comments near tanrule */
)
{ o[i] = cottosincos; ++i;
break;
}
switch(g)
{ case '+':
if(trigexpandflag & 1)
{ o[i] = cotcomplement; ++i;
if(topic != _trig_product)
{ o[i] = cotdif; ++i;
o[i] = cotsum; ++i;
}
if((!trigexpandflag & 0x0004) && !difflag)
{ o[i] = cottotan; ++i;
}
o[i] = cottosincos; ++i;
}
else if((trigexpandflag & 0x0004) && !difflag)
{ o[i] = cottotan; ++i;
o[i] = cottosincos; ++i;
}
set_trigflag(u,&localtrigflag);
if(ARCTRIGSPRESENT(localtrigflag))
{ o[i] = cotdif; ++i;
o[i] = cotsum; ++i;
o[i] = cottosincos; ++i;
}
break;
case '*':
if (trigexpandflag & 1)
{ o[i] = doublecot; ++i;
}
h = FUNCTOR(ARG(1,u));
if(h==ASIN || h==ACOS || h == ATAN || h == ASEC || h == ACSC || h==ACOT)
/* we must always expand cot(2 acot �) etc.; these
expressions sometimes arise in answers to integrals. */
{ o[i] = doublecot; ++i;
if(RATIONALP(ARG(0,u)) &&
ISINTEGER(ARG(1,ARG(0,u))) && ISEVEN(ARG(1,ARG(0,u)))
)
{ o[i] = cothalf1; ++i;
o[i] = cothalf2; ++i;
}
}
break;
}
break;
case TAN:
if(iscomplex(u) || contains_complexvar(u))
{ o[i] = itanh; ++i;
break;
}
if(pathlength >= 3 && path[pathlength-3] == ACOT)
{ /* simplify arccot(tan x) => arccot(cot(pi/2-x)) */
o[i] = tantocot2; ++i;
}
if(g == '+')
{ o[i] = tantocot; ++i;
}
if( g == '/' &&
(
(trigexpandflag & 1) ||
topic == _half_angle ||
(equals(ARG(1,u),two) && ARCTRIGFUNCTOR(FUNCTOR(ARG(0,u))))
/* tan(arcsin(x)/2) will simplify */
)
)
{ o[i] = tanhalf1; ++i;
o[i] = tanhalf2; ++i; /* used if tanhalf1 is inhibited */
}
/* Now for tanrule (tan=>sin/cos). The conditions
are somewhat intricate. */
if(!(trigexpandflag & 0x0010) &&
/* don't use it if only tan and sec are present */
!(trigexpandflag & 0x0004) &&
/* don't use it if only cot and tan are present */
limfractflag != -1 && /* don't use it in a limit of
fractions, but it's ok in a fraction of limits */
!difflag && /* don't use it inside derivatives, e.g.
d/dx cos(tan x) should not go to d/dx(cos(sin x/cos x))*/
(pathlength < 3 || !TRIGFUNCTOR(path[pathlength-3]))
/* don't use it e.g. in cos(tan x) even AFTER
derivatives are gone */
)
/* tanrule may be inhibited if in a sum containing only tan and sec */
{ o[i] = tanrule; ++i;
break;
}
else if(limitflag && get_whichpass() > 0)
{ o[i] = tanrule; ++i;
}
else if(iscomplex(u))
{ o[i] = tanrule; ++i;
}
else if((trigexpandflag & 0x01) && ! limitflag && g != '+')
/* Use it anyway if not all trig functions have the same arg */
/* but not inside a limit, else we can't solve
lim(x->0,tan(3x)/tan(2x)) properly; and in case g == '+',
we don't want to preempt tandif and tansum thrown in below. */
{ if(g == '*')
{ o[i] = doubletan; ++i;
}
o[i] = tanrule; ++i;
break;
}
switch(g)
{ case '+':
if(
(trigexpandflag & 1) ||
/* tan(deg(60) - deg(45)) etc. */
(ARITY(u)==2 && seminumerical(u))
)
{ if(topic != topic != _trig_product)
{ o[i] = tandif; ++i;
o[i] = tansum; ++i;
}
o[i] = tanrule; ++i;
/* tansum can fail if one of the new terms is undefined,
so throw in tanrule in any case. */
}
set_trigflag(u,&localtrigflag);
if(ARCTRIGSPRESENT(localtrigflag))
{ o[i] = tandif; ++i;
o[i] = tansum; ++i;
}
break;
case '*':
if(limitflag && (trigexpandflag & 1))
/* if !limitflag, it was already thrown in above, so as
to preempt tanrule */
{ o[i] = doubletan; ++i;
}
h = FUNCTOR(ARG(1,u));
if(h==ASIN || h==ACOS || h == ATAN || h == ASEC || h == ACSC || h==ACOT)
/* we must always expand tan(2 atan �) etc.; these
expressions sometimes arise in answers to integrals. */
{ o[i] = doubletan; ++i;
if(RATIONALP(ARG(0,u)) &&
ISINTEGER(ARG(1,ARG(0,u))) && ISEVEN(ARG(1,ARG(0,u)))
)
/* e.g., tan((1/4) arctan u) */
{ o[i] = tanhalf1; ++i;
o[i] = tanhalf2; ++i;
}
}
break;
case ATAN:
o[i] = tanatan; ++i;
break;
case ACOS:
o[i] = tanacos; ++i;
break;
case ASIN:
o[i] = tanasin; ++i;
break;
}
break;
case SIN:
if(pathlength >= 3 && path[pathlength-3] == ACOS)
{ /* simplify arccos(sin x) => arccos(cos(pi/2-x)) */
o[i] = sintocos2; ++i;
}
if(iscomplex(u) || contains_complexvar(u))
{ o[i] = isinh; ++i;
if(FUNCTOR(u) == '+')
{ o[i] = sindif; ++i;
o[i] = sinsum; ++i;
}
else
{ o[i] = complexsin; ++i;
}
break;
}
switch(g)
{ case '+' :
o[i] = sintocos; ++i; /* sin(�/2-�) = cos � */
if(
((trigexpandflag & 1) && topic != _trig_product) ||
/* sin(deg(60) - sin(45)) etc. */
(ARITY(u)==2 && seminumerical(u))
)
{ o[i] = sindif; ++i;
o[i] = sinsum; ++i;
}
else if(seminumerical(ARG(0,t)) && contains(t,DEG))
/* example: sin(60 degrees - 30 degrees), which
arises in evaluating sin(15 degrees) */
{ o[i] = sindif; ++i;
o[i] = sinsum; ++i;
}
else
{ set_trigflag(u,&localtrigflag);
if(ARCTRIGSPRESENT(localtrigflag))
{ o[i] = sindif; ++i;
o[i] = sinsum; ++i;
}
}
break;
case '*':
if((trigexpandflag & 1) &&
! difflag &&
(trigexpandflag & (1 << 12)) && /* only SIN and COS occur */
topic != _trig_product &&
problemtype != LIMITS &&
problemtype != LHOPITAL &&
(problemtype != INTEGRATION || intflag) &&
/* but don't put indexflag in because there's no use
expanding trig functions in indexed sums. */
/* we sometimes use reversedoublesin in limits,
and then we don't want to undo the result;
and AFTER doing an integral, we are perfectly
content with an answer like sin x + sin 4x,
but INSIDE an integral go ahead and
expand, e.g. 1/(sin x + sin 2x)
*/
(!SOLVETYPE(problemtype) || !stop_trigexpand())
/* Example: -sin x + 2 sin x sin 4x = 0, we must not
expand sin 4x before factoring the left side. The
factoring only happens in postops on the sum, so we
have to NOT expand sin 4x on pass 0. */
)
{ o[i] = doublesin; ++i;
if(!get_infractionflag())
{ o[i] = triplesin; ++i;
o[i] = expandsin; ++i;
}
/* sumofsin is now in pre_ops so it's
safe to use these here even though
sin 5x + sin 3x = 0 should not be solved
by expanding but by combining.
*/
}
h = FUNCTOR(ARG(1,u));
if(h==ASIN || h==ACOS || h == ATAN || h == ASEC || h == ACSC || h==ACOT)
/* we must always expand sin(2 asin �) etc.; these
expressions sometimes arise in answers to integrals. */
{ o[i] = doublesin; ++i;
if(RATIONALP(ARG(0,u)) &&
ISINTEGER(ARG(1,ARG(0,u))) && ISEVEN(ARG(1,ARG(0,u)))
/* e.g., sin((1/4) arctan u) */
)
{ o[i] = sinhalf1; ++i;
o[i] = sinhalf2; ++i;
}
}
if(ARITY(u) == 2 && equals(ARG(1,u),pi) &&
RATIONALP(ARG(0,u)) && equals(ARG(0,ARG(0,u)),three) &&
ispoweroftwo(ARG(1,ARG(0,u)))
)
{ o[i] = triplesin; ++i; /* evaluate sin((3/8) pi) for example */
}
else if(ARITY(u) == 2 && equals(ARG(1,u),pi) &&
RATIONALP(ARG(0,u)) && equals(ARG(0,ARG(0,u)),two) &&
equals(ARG(1,ARG(0,u)),three)
)
{ o[i] = doublesin; ++i; /* evaluate sin((2/3) pi) */
}
break;
case '/':
if(ISINTEGER(ARG(1,u)) && ISEVEN(ARG(1,u)))
{ if((trigexpandflag & 1) || contains_arctrigs(u))
{ o[i] = sinhalf1; ++i;
o[i] = sinhalf2; ++i;
}
if(equals(ARG(0,u),pi) && ISINTEGER(ARG(1,u)) &&
(ispoweroftwo(ARG(1,u)) ||
INTDATA(ARG(1,u)) == 12
)
)
{ o[i] = sinhalf1; ++i;
/* get e.g. sin(pi/8) and sin(pi/12) evaluated */
}
}
break;
case ATAN:
o[i] = sinatan; ++i;
break;
case ACOS:
o[i] = sinacos; ++i;
break;
case ASIN:
o[i] = sinasin; ++i;
break;
}
break;
case COS:
if(pathlength >= 3 && path[pathlength-3] == ASIN)
{ /* simplify arcsin(cos x) => arcsin(sin(pi/2-x)) */
o[i] = costosin2; ++i;
}
if(iscomplex(u) || contains_complexvar(u))
{ o[i] = icosh; ++i;
if(FUNCTOR(u) == '+')
{ o[i] = cosdif; ++i;
o[i] = cossum; ++i;
}
else
{ o[i] = complexcos; ++i;
}
break;
}
switch(g)
{ case '+' :
o[i] = costosin; ++i; /* cos(�/2-�) = sin � */
if(
((trigexpandflag & 1) && topic != _trig_product) ||
/* cos(deg(60) - deg(45)) etc. */
(ARITY(u)==2 && seminumerical(u))
)
{ o[i] = cosdif; ++i;
o[i] = cossum; ++i;
}
set_trigflag(u,&localtrigflag);
if(ARCTRIGSPRESENT(localtrigflag))
{ o[i] = cosdif; ++i;
o[i] = cossum; ++i;
}
break;
case '*':
if((trigexpandflag & 1) &&
! difflag &&
(trigexpandflag & (1 << 12)) && /* only SIN and COS occur */
topic != _trig_product &&
problemtype != LIMITS &&
problemtype != LHOPITAL &&
(problemtype != INTEGRATION || intflag) &&
/* but don't but indexflag in because there's no use
expanding trig functions in indexed sums. */
/* we sometimes use reversedoublesin in limits,
and then we don't want to undo the result;
and AFTER doing an integral, we are perfectly
content with an answer like sin x + sin 4x,
but INSIDE an integral go ahead and
expand, e.g. 1/(sin x + sin 2x)
*/
(!SOLVETYPE(problemtype) || !stop_trigexpand())
/* Example: -sin x + 2 sin x sin 4x = 0, we must not
expand sin 4x before factoring the left side. The
factoring only happens in postops on the sum, so we
have to NOT expand sin 4x on pass 0. */
)
{ if(trigexpandflag & 2) /* only one trig function occurs,
which perforce is COS */
{ o[i] = doublecos3; ++i; /* cos 2t = 2cos^2 t-1 */
}
else if(FUNCTOR(ARG(1,u)) == ACOS)
{ o[i] = doublecos3; ++i; /* cos(2 arccos t) = 2(cos^arccos t)^2 - 1 */
}
else if(FUNCTOR(ARG(1,u)) == ASIN)
{ o[i] = doublecos2; ++i; /* cos(2 arcsin t) = 1- 2sin^2(arcsin t) */
}
else if(sincosflag == SIN)
{ o[i] = doublecos2; ++i;
}
else if(sincosflag == COS)
{ o[i] = doublecos3; ++i;
}
else
{ o[i] = doublecos1; ++i; /* cos 2t = cos^2 t - sin^2 t */
}
/* sumofcos is now in pre_ops, so will not be
pre-empted here. This is good as an equation
like cos 5x + cos 3x = 0 should not be
solved by expanding but by combining.
*/
if(!get_infractionflag())
{ o[i] = triplecos; ++i;
o[i] = expandcos; ++i;
}
}
h = FUNCTOR(ARG(1,u));
if(h == ACOS)
{ o[i] = doublecos3; ++i; /* cos(2 arccos t) = 2(cos^arccos t)^2 - 1 */
if(RATIONALP(ARG(0,u)) &&
ISINTEGER(ARG(1,ARG(0,u))) && ISEVEN(ARG(1,ARG(0,u)))
)
/* e.g., cos((1/4) arctan u) */
{ o[i] = coshalf1; ++i;
o[i] = coshalf2; ++i;
}
}
else if(h == ASIN)
{ o[i] = doublecos2; ++i; /* cos(2 arcsin t) = 1- 2sin^2(arcsin t) */
if(RATIONALP(ARG(0,u)) &&
ISINTEGER(ARG(1,ARG(0,u))) && ISEVEN(ARG(1,ARG(0,u)))
)
/* e.g., cos((1/4) arctan u) */
{ o[i] = coshalf1; ++i;
o[i] = coshalf2; ++i;
}
}
if(h == ATAN || h == ASEC || h == ACSC || h==ACOT)
/* we must always expand cos(2 acos �) etc.; these
expressions sometimes arise in answers to integrals. */
{ o[i] = doublecos1; ++i;
if(RATIONALP(ARG(0,u)) &&
ISINTEGER(ARG(1,ARG(0,u))) && ISEVEN(ARG(1,ARG(0,u)))
)
/* e.g., cos((1/4) arctan u) */
{ o[i] = coshalf1; ++i;
o[i] = coshalf2; ++i;
}
}
if(ARITY(u) == 2 && equals(ARG(1,u),pi) &&
RATIONALP(ARG(0,u)) && equals(ARG(0,ARG(0,u)),three) &&
ispoweroftwo(ARG(1,ARG(0,u)))
)
{ o[i] = triplecos; ++i; /* evaluate cos((3/8) pi) for example */
}
else if(ARITY(u) == 2 && equals(ARG(1,u),pi) &&
RATIONALP(ARG(0,u)) && equals(ARG(0,ARG(0,u)),two) &&
equals(ARG(1,ARG(0,u)),three)
)
{ o[i] = doublecos1; ++i; /* evaluate cos((2/3) pi) */
}
break;
case '/':
if(ISINTEGER(ARG(1,u)) && ISEVEN(ARG(1,u)))
{ if((trigexpandflag & 1) || contains_arctrigs(u))
{ o[i] = coshalf1; ++i;
o[i] = coshalf2; ++i;
}
if(equals(ARG(0,u),pi) && ISINTEGER(ARG(1,u)) &&
(ispoweroftwo(ARG(1,u)) ||
INTDATA(ARG(1,u)) == 12
)
)
{ o[i] = coshalf1; ++i;
/* get e.g. cos(pi/8) and cos(pi/12) evaluated */
}
}
break;
case ATAN:
o[i] = cosatan; ++i;
break;
case ACOS:
o[i] = cosacos; ++i;
break;
case ASIN:
o[i] = cosasin; ++i;
break;
}
break;
}
*nops = i;
}
/*___________________________________________________________________________*/
MEXPORT_AUTOMODE int contains_complexvar(term t)
/* return 1 if t contains a variable with type DCOMPLEX */
{ unsigned short n;
int i;
if(ISATOM(t) && TYPE(t) == DCOMPLEX)
return 1;
if(ATOMIC(t))
return 0;
n = ARITY(t);
for(i=0;i<n;i++)
{ if(contains_complexvar(ARG(i,t)))
return 1;
}
return 0;
}
/*__________________________________________________________________*/
static int stop_trigexpand(void)
/* return 1 if the active line has the form sum = 0 and the
sum will content_factor. (In that case, we don't want to expand
trig functions like sin 4x, because after the content-factoring,
they may be isolated in an equation containing only trig functions of 4x.)
*/
{ term u = history(get_activeline());
term t,a,b;
int k,err;
unsigned short const *path = get_path();
int pathlength = get_pathlength();
if(pathlength == 0)
return 0;
if(path[0] == '=')
{ k = path[1] == 2 ? 0 : 1;
if(ZERO(ARG(k,u)))
t = ARG(path[1] - 1,u);
else
return 0;
}
else if(path[0] == OR)
{ u = ARG(path[1] - 1,u);
if(pathlength < 3)
return 0;
k = path[3] == 2 ? 0 : 1;
if(ZERO(ARG(k,u)))
t = ARG(path[3] - 1, u);
else
return 0;
}
err = content_factor(t,&a,&b);
return err ? 0 : 1;
}
/*______________________________________________________________________________*/
static int ispoweroftwo(term t)
/* return 1 if t is a nonzero integer which is a power of two.
Don't count bignums. Return 0 otherwise. */
{ long m;
if(!ISINTEGER(t))
return 0;
m = INTDATA(t);
if(m == 0)
return 0;
while(!(m & 1))
{ m = m >> 1;
}
m = m >> 1;
if(m == 0)
return 1;
return 0;
}
Sindbad File Manager Version 1.0, Coded By Sindbad EG ~ The Terrorists