Sindbad~EG File Manager
/* operators for infinite limits and limits at infinity, for MathXpert */
/* M. Beeson
1.15.92 Original date
10.21.99 modified
1.4.00 corrected addinfinity
4.18.00 corrected sumleadingterm, adding if(!ZERO(a)) x = sum(x,tnegate(a)); in two places
4.21.00 removed superfluous variables from use_comdenom_instead
4.21.00 corrected the 4.18 correction
1.29.06 rewrote use_comdenom_instead.
6.9.13 modified invert_lim to create a new variable if the original one has type INTEGER
6.10.13 modified invert_lim to fail if the limitand contains an integral.
3.19.23 changed get_mathmode to get_mathmode() in sumleadingterm
5.11.24 corrected \to to \\to in reason of limlnsin
*/
#include <string.h>
#include <assert.h>
#include <math.h>
#include "globals.h"
#include "ops.h"
#include "calc.h"
#include "prover.h"
#include "order.h"
#include "sqrts.h" /* grf_aux */
#include "mplimits.h"
#include "symbols.h"
#include "mathmode.h" /* get_mathmode */
#include "errbuf.h"
#include "binders.h" /* get_limit_info */
#include "pvalaux.h" /* isodd */
#include "autosimp.h" /* SetShowStepOperation */
#include "pathtail.h"
#include "algaux.h" /* path_to_difference */
#include "dispfunc.h" /* functor_string */
#include "probtype.h"
#include "loglead.h" /* log_leading_term */
#include "polynoms.h" /* ispolyin */
static int limunary_aux(unsigned short g, term t, term *next, char *reason);
/*_________________________________________________________________*/
int limquoinfinite(term t, term arg, term *next, char *reason)
/* lim u/v when lim v = 0, lim u !=0 */
/* works only when limval can get the limits of num or denom */
/* watch out for things like lim(x->0, 1/(x sin^2 x)) which
fails to exist because the denominator isn't defined in a nbhd */
{ int err;
term num,den;
term w,u,v; /* t = lim(x->a,u/v) or lim(x->a,dir,u/v) */
if(FUNCTOR(t) != LIMIT)
return 1;
w = LIMITAND(t);
if(FUNCTOR(w) != '/')
return 1;
u = ARG(0,w);
if(OBJECT(u))
{ num = u;
err = 0;
}
else if(ARITY(t)==2)
err = limval(limit(ARG(0,t),u),&num);
else
err = limval(limit3(ARG(0,t),ARG(1,t),u),&num);
if(err)
{ errbuf(0, english(951));
/* Can't calculate limit of numerator */
return 1;
}
if(equals(num,zero))
{ errbuf(0, english(838)); /* Limit of numerator is zero. */
return 1;
}
v = ARG(1,w);
if(ARITY(t)==2)
err = limval(limit(ARG(0,t),v),&den);
else
err = limval(limit3(ARG(0,t),ARG(1,t),v),&den);
if(err)
{ errbuf(0, english(947));
/* Can't calculate limit of denominator. */
return 1;
}
if(!equals(den,zero))
{ errbuf(0, english(839));
/* Limit of denominator is not zero. */
return 1;
}
err = limval(t,next); /* wastefully duplicates the computation above,
but we need to know if the limit is infinity,
minusinfinity, undefined or unbounded_oscillations */
assert(!err); /* we can calculate the limit of numerator and denom
so at worst we will get undefined */
HIGHLIGHT(*next);
if(OBJECT(num))
strcpy(reason, equals(*next,infinity) ? english(945) :
equals(*next,minusinfinity) ? english(946) :
english(947));
/* 1/u\\to \\infty if u>0 and u\\to 0
1/u\\to -\\infty if u<0 and u\\to 0
lim 1/u undefined if lim u=0 */
else if(equals(*next,infinity))
strcpy(reason,english(949));
/* u/v\\to \\infty if v lim u > 0 and v\\to 0 */
else if(equals(*next,minusinfinity))
strcpy(reason,english(950));
/* u/v\\to -\\infty if v lim u < 0 and u\\to 0 */
else
strcpy(reason, english(841));
/* lim u/v undefined if v\\to 0 and not u\\to 0 */
return 0;
}
/*__________________________________________________________________*/
int inflimpower1(term t, term arg, term *next, char *reason)
/* 1/x^n -> 0 as x->\\infty (n>0) */
/* Also works on x^(-n) */
{ term u,x,a,n,c,s;
int err;
if(FUNCTOR(t) != LIMIT)
return 1;
a = ARG(1,ARG(0,t));
if(!equals(a,infinity) && !equals(a,minusinfinity))
return 1;
assert(ARITY(t)==2); /* limits at infinity are never one-sided */
u = LIMITAND(t);
x = ARG(0,ARG(0,t));
if(FUNCTOR(u) == '^' && equals(ARG(0,u),x))
{ err = infer(lessthan(ARG(1,u),zero));
if(err)
return 1;
goto out;
}
if(FUNCTOR(u) != '/')
return 1;
if(depends(ARG(0,u),x))
return 1;
ncs(ARG(1,u),&n,&c,&s);
if(equals(s,x))
goto out;
if(FUNCTOR(s) == '^' && equals(ARG(0,s),x))
{ err = infer(positive(ARG(1,s)));
if(!err)
goto out;
errbuf(0, english(842));
/* Exponent in denominator must be positive */
return 1;
}
return 1;
out:
*next = zero;
HIGHLIGHT(*next);
if(equals(a,infinity))
strcpy(reason, english(959)); /* 1/x \\to 0 as x\\to \\infty (n>0) */
else /* a is minusinfinity */
strcpy(reason, english(960)); /* 1/x^n\\to 0 as x\to -\\infty (n>0) */
return 0;
}
/*__________________________________________________________________*/
int inflimpower2(term t, term arg, term *next, char *reason)
/* lim(x\to \infty ,x^n) = \\infty if n \ge 1 */
{ term u,x,a;
int err;
if(FUNCTOR(t) != LIMIT)
return 1;
a = ARG(1,ARG(0,t));
if(!equals(a,infinity) && !equals(a,minusinfinity))
return 1;
assert(ARITY(t)==2); /* limits at infinity are never one-sided */
u = LIMITAND(t);
x = ARG(0,ARG(0,t));
if(equals(u,x))
{ *next = equals(a,infinity) ? infinity : minusinfinity;
if(equals(a,infinity))
{ strcpy(reason, "$lim (x\\to \\infty ,x) = \\infty $");
*next = infinity;
}
else
{ strcpy(reason, "$lim (x\\to -\\infty ,x) = -\\infty $");
*next = minusinfinity;
}
HIGHLIGHT(*next);
return 0;
}
if(FUNCTOR(u) != '^')
return 1;
if(!equals(ARG(0,u),x))
return 1;
err = infer(positive(ARG(1,u)));
if(err)
{ errbuf(0, english(843));
/* Exponent must be positive */
return 1;
}
if(equals(a,infinity))
{ *next = infinity;
HIGHLIGHT(*next);
strcpy(reason, english(961)); /* x\\to \\infty as x\\to \\infty (n>0) */
return 0;
}
err = infer(even(ARG(1,u)));
if(!err)
{ strcpy(reason, english(962)); /* x^(2n) \\to \\infty as x\\to -\\infty (n>0) */
*next = infinity;
HIGHLIGHT(*next);
return 0;
}
err =infer(odd(ARG(1,u)));
if(!err)
{ strcpy(reason, english(963)); /* x^n \\to -\\infty as x\\to -\\infty */
strcat(reason, english(952)); /* (n odd and positive) */
*next = minusinfinity;
HIGHLIGHT(*next);
return 0;
}
*next = undefined;
HIGHLIGHT(*next);
errbuf(0, english(953));
/* Can't determine the sign of the exponent */
return 0;
}
/*__________________________________________________________________*/
int invertlim(term t, term arg, term *next, char *reason)
/* lim(x->infinity,f(x)) = lim(x->0+,f(1/x)) */
{ term u,x,v,a,dir,z;
if(FUNCTOR(t) != LIMIT)
return 1;
a = ARG(1,ARG(0,t));
if(!equals(a,infinity) && !equals(a,minusinfinity))
return 1;
assert(ARITY(t)==2); /* limits at infinity are never one-sided */
u = LIMITAND(t);
if(contains(u,DIFF))
{ errbuf(0, english(1410));
/* You must first evaluate the derivative or derivatives */
return 1;
}
if(contains(u,INTEGRAL) || contains(u,SUM))
return 1; // no error message needed as it won't be on the Term Selection menu in that case
x = ARG(0,ARG(0,t));
if(TYPE(x)==INTEGER)
{ /* then you must introduce a new variable whose type is not INTEGER, or
wrong inferences may be made, since the prover thinks for example ln n >= 0,
which won't be true if n is allowed to be near 0 and not be an integer.
*/
z = getnewboundvar(x,"xtuvzy");
}
else
z = x;
subst(make_fraction(one,z),x,u,&v);
dir = equals(a,infinity) ? right : left;
*next = limit3(arrow(z,zero),dir,v);
HIGHLIGHT(*next);
if(equals(a,infinity))
strcpy(reason, "$lim(x\\to \\infinity,f(x))$ = $lim(x\\to 0+,f(1/x))$");
else
strcpy(reason, "$lim(x\\\to-\\infinity,f(x))$ = $lim(x\\to 0-,f(1/x))$");
return 0;
}
/*__________________________________________________________*/
int liminverseevenpower(term t, term arg, term *next, char *reason)
/* lim (1/u^2^n) = \\infty if u->0 */
{ term u,v,x;
int err;
if(FUNCTOR(t) != LIMIT)
return 1;
if(ARITY(t) != 2)
return 1;
u = LIMITAND(t);
x = ARG(0,ARG(0,t));
if(FUNCTOR(u) != '/')
return 1;
if(depends(ARG(0,u),x))
return 1;
v = ARG(1,u);
if(FUNCTOR(v) != '^')
return 1;
err = infer(even(ARG(1,v)));
if(err)
return 1;
err = limquoinfinite(t,arg,next,reason);
if(err)
return 1;
strcpy(reason, english(964)); /* lim (1/u^2^n)=\\infty if u\\to \60 */
return 0;
}
/*__________________________________________________________*/
int liminverseoddpower(term t, term arg, term *next, char *reason)
/* lim(1/u^n) undefined if u->0, n odd */
{ term u,v,x;
int err;
if(FUNCTOR(t) != LIMIT)
return 1;
if(ARITY(t)!= 2)
return 1;
u = LIMITAND(t);
x = ARG(0,ARG(0,t));
if(FUNCTOR(u) != '/')
return 1;
if(depends(ARG(0,u),x))
return 1;
v = ARG(1,u);
if(FUNCTOR(v) != '^')
return 1;
err = infer(odd(ARG(1,v)));
if(err)
return 1;
err = limquoinfinite(t,arg,next,reason);
if(err)
return 1;
strcpy(reason, english(844));
/* lim(1/u^n) undefined if u\\to \60, n odd */
return 0;
}
/*__________________________________________________________*/
int lim1inverseleft(term t, term arg, term *next, char *reason)
/* lim(x->a-,1/u^n)=-\\infty , u->0, n odd */
{ term u,v,x;
int err;
if(FUNCTOR(t) != LIMIT)
return 1;
if(ARITY(t)!= 3)
return 1;
if(FUNCTOR(ARG(1,t)) != LEFT)
return 1;
u = LIMITAND(t);
x = ARG(0,ARG(0,t));
if(FUNCTOR(u) != '/')
return 1;
if(depends(ARG(0,u),x))
return 1;
v = ARG(1,u);
if(FUNCTOR(v) != '^')
return 1;
err = limquoinfinite(t,arg,next,reason);
if(err)
return 1;
strcpy(reason, english(844));
/* lim(1/u^n) undefined if u\\to \60, n odd */
return 0;
}
/*__________________________________________________________*/
int lim1inverseright(term t, term arg, term *next, char *reason)
/* lim(x->a+,1/u^n) = \\infty if u->0 */
{ term u,v,x;
int err;
if(FUNCTOR(t) != LIMIT)
return 1;
if(ARITY(t)!= 3)
return 1;
if(FUNCTOR(ARG(1,t)) != RIGHT)
return 1;
u = LIMITAND(t);
x = ARG(0,ARG(0,t));
if(FUNCTOR(u) != '/')
return 1;
if(depends(ARG(0,u),x))
return 1;
v = ARG(1,u);
if(FUNCTOR(v) != '^')
return 1;
err = limquoinfinite(t,arg,next,reason);
if(err)
return 1;
strcpy(reason, english(844));
/* lim(1/u^n) undefined if u\\to \60, n odd */
return 0;
}
/*___________________________________________________________________*/
int limlnsing(term t, term arg, term *next, char *reason)
/* limit of ln at zero */
{ term u,v,mid,ans;
int err;
if(FUNCTOR(t)!= LIMIT)
return 1;
u = LIMITAND(t);
if(FUNCTOR(u) != LN)
return 1;
v = ARG(0,u);
mid = ARITY(t)==2 ? limit(ARG(0,t),v) : limit3(ARG(0,t),ARG(1,t),v);
err = limval(mid,&ans);
if(err)
return 1;
if(!ZERO(ans))
return 1;
*next = minusinfinity;
HIGHLIGHT(*next);
strcpy(reason,"$lim(x\\to 0^+,ln x) = -\\infty $");
return 0;
}
/*___________________________________________________________________*/
int limtansing(term t, term arg, term *next, char *reason)
/* limit of tan at a singularity */
/* lim(x->(2n+1) pi/2, tan x) = \pm \\infty but with signs switched */
{ int err;
term a,x,u,v;
unsigned short n;
if(FUNCTOR(t)!=LIMIT)
return 1;
a = ARG(1,ARG(0,t));
x = ARG(0,ARG(0,t));
u = LIMITAND(t);
n = ARITY(t);
if(FUNCTOR(u) != TAN)
return 1;
if(!equals(x,ARG(0,u)))
return 1;
/* Now determine if a is an odd multiple of pi/2 */
polyval(make_fraction(product(two,a),pi_term),&v);
err = infer(odd(v));
if(err)
{ errbuf(0, english(845));
/* Can't check limit is at an odd multiple of \pi /2. */
return 1;
}
if(n==2)
{ *next = undefined;
commentbuf(0, english(846));
/* The one-sided limits have different signs. */
}
else if(equals(ARG(1,t),left))
*next = infinity;
else
*next = minusinfinity;
HIGHLIGHT(*next);
strcpy(reason,"$$lim(x->(2n+1)pi/2");
if(equals(ARG(1,t),left))
strcat(reason,"-, tan x) = infinity$$");
else if(equals(ARG(1,t),right))
strcat(reason,"+,tan x) = -infinity$$");
else
strcat(reason,"tan x) = undefined$$");
return 0;
}
/*___________________________________________________________________*/
int limcotsing(term t, term arg, term *next, char *reason)
/* limit of cot at a singularity */
/* lim(x->n\pi \pm ,cot x) = \pm \\infty */
{ int err;
term a,x,u,v;
unsigned short n;
if(FUNCTOR(t)!=LIMIT)
return 1;
a = ARG(1,ARG(0,t));
x = ARG(0,ARG(0,t));
u = LIMITAND(t);
n = ARITY(t);
if(FUNCTOR(u) != COT)
return 1;
if(!equals(x,ARG(0,u)))
return 1;
/* Now determine if a is a multiple of pi */
polyval(make_fraction(a,pi_term),&v);
err = infer(type(v,INTEGER));
if(err)
{ errbuf(0, english(847));
/* Can't check limit is at a multiple of \pi */
return 1;
}
if(n==2)
{ *next = undefined;
commentbuf(0, english(846));
/* The one-sided limits have different signs. */
strcpy(reason,"$$lim(x-> n pi,cot x)=undefined$$");
}
else if(equals(ARG(1,t),left))
{ *next = minusinfinity;
strcpy(reason,"$$lim(x-> n pi-,cot x)=-infinity$$");
}
else
{ *next = infinity;
strcpy(reason,"$$lim(x-> n pi+,cot x)= infinity$$");
}
HIGHLIGHT(*next);
return 0;
}
/*___________________________________________________________________*/
int limcscsing(term t, term arg, term *next, char *reason)
/* limit of csc at a singularity */
/* "lim(x->n\pi \pm ,csc x) = \pm \\infty */
/* The limit depends on the direction and on whether n is odd or even */
{ int err;
term a,x,u,v;
unsigned short n;
if(FUNCTOR(t)!=LIMIT)
return 1;
a = ARG(1,ARG(0,t));
x = ARG(0,ARG(0,t));
u = LIMITAND(t);
n = ARITY(t);
if(FUNCTOR(u) != CSC)
return 1;
if(!equals(x,ARG(0,u)))
return 1;
/* Now determine if a is a multiple of pi */
polyval(make_fraction(a,pi_term),&v);
err = infer(type(v,INTEGER));
if(err)
{ errbuf(0, english(847));
/* Can't check limit is at a multiple of \pi */
return 1;
}
if(n==2)
{ *next = undefined;
commentbuf(0, english(846));
/* The one-sided limits have different signs. */
HIGHLIGHT(*next);
strcpy(reason,"$$lim(x->n pi,csc x) = undefined$$");
}
/* Now we must determine if v is odd or even */
if(iseven(v))
{ /* v is even , so a == 0 mod 2\pi */
if(equals(ARG(1,t),left))
{ *next = minusinfinity;
strcpy(reason,"$$lim(x-> 0-,csc x) = -infinity$$");
HIGHLIGHT(*next);
return 0;
}
else /* limit from right at 0 */
{ *next = infinity;
HIGHLIGHT(*next);
strcpy(reason,"$$lim(x-> 0+,csc x) = infinity$$");
return 0;
}
}
/* Now v is not even */
if(isodd(v))
{ if(equals(ARG(1,t),left))
{ *next = infinity;
strcpy(reason,"$$lim(x-> pi-,csc x) = infinity$$");
HIGHLIGHT(*next);
return 0;
}
else /* limit from the right */
{ *next = minusinfinity;
strcpy(reason,"$$lim(x->pi+,csc x) = -infinity$$");
HIGHLIGHT(*next);
return 0;
}
}
/* can't determine if it's odd or even */
*next = undefined;
strcpy(reason,"$$lim(x->n pi,csc x)= undefined$$");
HIGHLIGHT(*next);
return 0;
}
/*___________________________________________________________________*/
int limsecsing(term t, term arg, term *next, char *reason)
/* limit of sec at a singularity */
/* lim(x->(2n+1)\pi /2 \pm ,sec x) = \pm \\infty */
{ int err;
term a,x,u,v;
unsigned short n;
if(FUNCTOR(t)!=LIMIT)
return 1;
a = ARG(1,ARG(0,t));
x = ARG(0,ARG(0,t));
u = LIMITAND(t);
n = ARITY(t);
if(FUNCTOR(u) != SEC)
return 1;
if(!equals(x,ARG(0,u)))
return 1;
/* Now determine if a is an odd multiple of pi/2 */
polyval( sum(make_fraction(a,pi_term),tnegate(make_fraction(one,two))),&v);
err = infer(type(v,INTEGER));
if(err)
{ errbuf(0, english(848));
/* Can't check limit is at an odd multiple of \pi /2 */
return 1;
}
if(n==2)
{ *next = undefined;
commentbuf(0, english(846));
/* The one-sided limits have different signs. */
HIGHLIGHT(*next);
strcpy(reason, "$$lim(x->(2n+1)pi/2, sec x) = undefined$$");
return 0;
}
/* Now we have a one-sided limit to deal with. We must know
whether v is odd or even. */
if(iseven(v))
{ /* Now v is even where a = (2v+1)\pi /2 so a = \pi /2 mod 2\pi */
if(equals(ARG(1,t),left))
{ *next = minusinfinity;
strcpy(reason,"$$lim(x-> pi/2-, sec x) = -infinity$$");
HIGHLIGHT(*next);
return 0;
}
else /* if(equals(ARG(1,t),right)) */
{ *next = infinity;
strcpy(reason, "$$lim(x-> pi/2+, sec x) = infinity$$");
HIGHLIGHT(*next);
return 0;
}
}
if(isodd(v))
/* Now v is odd, where a = (2v+1)\pi /2, so a = -\pi /2 mod 2\pi */
{ if(equals(ARG(1,t),left))
{ *next = minusinfinity;
strcpy(reason,"$$lim(x-> -pi/2-, sec x) =-infinity$$");
HIGHLIGHT(*next);
return 0;
}
else
{ *next = infinity;
strcpy(reason,"$$lim(x-> -pi/2+, sec x) = infinity$$");
HIGHLIGHT(*next);
return 0;
}
}
/* can't determine whether v is odd or even */
*next = undefined;
commentbuf(0, english(1100));
/* Limit has different signs at \pm \pi /2 */
HIGHLIGHT(*next);
strcpy(reason,english(1099)); /* see above */
return 0;
}
/*___________________________________________________________________*/
int limexpinf(term t, term arg, term *next, char *reason)
/* lim(x->\\infty ,e^x) = \\infty */
{ term u,v,mid,ans;
int err;
if(FUNCTOR(t)!= LIMIT && FUNCTOR(t)!= '^')
return 1;
if(FUNCTOR(t)=='^')
{ if(!equals(ARG(0,t),eulere))
return 1;
u = ARG(1,t);
if(!NOTDEFINED(u))
return 1;
*next = u;
if(equals(u,infinity))
{ strcpy(reason,english(965)); /* e^x\to \\infty as x\to \\infty */
*next = infinity;
}
else
return 1;
HIGHLIGHT(*next);
return 0;
}
/* Now FUNCTOR(t)==LIM */
u = LIMITAND(t);
if(FUNCTOR(u) != '^' || !equals(ARG(0,u),eulere))
return 1;
v = ARG(1,u);
mid = ARITY(t)==2 ? limit(ARG(0,t),v) : limit3(ARG(0,t),ARG(1,t),v);
err = limval(mid,&ans);
if(err)
return 1;
if(!NOTDEFINED(ans))
return 1;
*next = ans;
if (equals(ans,infinity))
strcpy(reason,english(965)); /* e^x\to \\infty as x\to \\infty */
else
return 1;
HIGHLIGHT(*next);
return 0;
}
/*___________________________________________________________________*/
int limexpinf2(term t, term arg, term *next, char *reason)
/* and lim(x->-\\infty ,e^x) = 0 */
{ term u,v,mid,ans;
int err;
if(FUNCTOR(t)!= LIMIT && FUNCTOR(t)!= '^')
return 1;
if(FUNCTOR(t)=='^')
{ if(!equals(ARG(0,t),eulere))
return 1;
u = ARG(1,t);
if(!NOTDEFINED(u))
return 1;
*next = u;
if(equals(u,minusinfinity))
{ strcpy(reason,english(966)); /* e^x\to \60 as x\to -\\infty */
*next = zero;
}
else
return 1;
HIGHLIGHT(*next);
return 0;
}
/* Now FUNCTOR(t)==LIMIT */
u = LIMITAND(t);
if(FUNCTOR(u) != '^' || !equals(ARG(0,u),eulere))
return 1;
v = ARG(1,u);
mid = ARITY(t)==2 ? limit(ARG(0,t),v) : limit3(ARG(0,t),ARG(1,t),v);
err = limval(mid,&ans);
if(err)
return 1;
if(!NOTDEFINED(ans))
return 1;
if (!equals(ans,minusinfinity))
return 1;
strcpy(reason,english(966)); /* e^x\to \60 as x\to -\\infty */
*next = zero;
HIGHLIGHT(*next);
return 0;
}
/*___________________________________________________________________*/
int limlnright(term t, term arg, term *next, char *reason)
/* lim(x->\\infty ,ln x) = \\infty */
{ if(FUNCTOR(t)!= LIMIT && FUNCTOR(t)!= LN)
return 1;
return limunary_aux(LN,t,next,reason);
}
/*___________________________________________________________________*/
int limarctaninf(term t, term arg, term *next, char *reason)
/* lim(x->\\infty ,arctan x) = pi_term/2 */
{ if(FUNCTOR(t)!= LIMIT && FUNCTOR(t)!= ATAN)
return 1;
return limunary_aux(ATAN,t,next,reason);
}
/*___________________________________________________________________*/
int limtanhinf(term t, term arg, term *next, char *reason)
/* lim(x->\\infty ,tanh x) = 1 */
{ if(FUNCTOR(t)!= LIMIT && FUNCTOR(t)!= TANH)
return 1;
return limunary_aux(TANH,t,next,reason);
}
/*___________________________________________________________________*/
int limarccotinf(term t, term arg, term *next, char *reason)
/* lim(x->\\infty ,arccot x) = 0 */
{ if(FUNCTOR(t)!= LIMIT && FUNCTOR(t)!= ACOT)
return 1;
if(!equals(ARG(1,ARG(0,t)),infinity))
return 1;
return limunary_aux(ACOT,t,next,reason);
}
/*___________________________________________________________________*/
int limarccotinf2(term t, term arg, term *next, char *reason)
/* lim(x->-\\infty ,arccot x) = \pi */
{ if(FUNCTOR(t)!= LIMIT && FUNCTOR(t)!= ACOT)
return 1;
if(!equals(ARG(1,ARG(0,t)),minusinfinity))
return 1;
return limunary_aux(ACOT,t,next,reason);
}
/*___________________________________________________________________*/
int limsqrtinf(term t, term arg, term *next, char *reason)
/* lim(x->\\infty ,\sqrt x) = \\infty */
{ if(FUNCTOR(t)!= LIMIT && FUNCTOR(t)!= SQRT)
return 1;
return limunary_aux(SQRT,t,next,reason);
}
/*___________________________________________________________________*/
int limrootinf(term t, term arg, term *next, char *reason)
/* lim(x->\\infty , root(n,x)) = \\infty */
{ if(FUNCTOR(t)!= LIMIT && FUNCTOR(t)!= ROOT)
return 1;
return limunary_aux(ROOT,t,next,reason);
}
/*___________________________________________________________________*/
static int limunary_aux(unsigned short g, term t, term *next, char *reason)
/* finish off a limit at infinity of g(x) */
/* g is either LN, ROOT, SQRT, ATAN, or TANH */
/* t is either a limit or a ln, arctan, root, or sqrt of infinity */
{ unsigned short f = FUNCTOR(t);
term u,v,mid,ans;
int err;
if(f==LN || f== SQRT || f == ROOT || f == ATAN || f == TANH || f == ACOT)
{ u = (f==ROOT ? ARG(1,t) : ARG(0,t));
if(!NOTDEFINED(u))
return 1;
if(equals(u,infinity))
{ switch(f)
{ case LN:
strcpy(reason, "$$lim(t->infinity,ln t) = infinity$$");
*next = infinity;
break;
case SQRT:
strcpy(reason, "$$lim(t->infinity,sqrt t) = infinity$$");
*next = infinity;
break;
case ROOT:
strcpy(reason, "$$lim(t->infinity,root(n,t)) = infinity$$");
*next = infinity;
break;
case ATAN:
strcpy(reason,"$$lim(x->infinity,arctan x)=\\pi/2$$");
*next = make_fraction(pi_term,two);
break;
case ACOT:
strcpy(reason,"$$lim(x->infinity,arccot x)=0$$");
*next = zero;
break;
case TANH:
strcpy(reason,"$$lim(x->infinity,tanh x) = 1$$");
*next = one;
break;
}
}
else if(f == ATAN && equals(u,minusinfinity))
{ strcpy(reason,"$$lim(x->-infinity,arctan x)=-\\pi/2$$");
*next = tnegate(make_fraction(pi_term,two));
}
else if(f == TANH && equals(u,minusinfinity))
{ strcpy(reason,"$$lim(x->-infinity,tanh x) = -1$$");
*next = minusone;
}
else if(f == ACOT && equals(u,minusinfinity))
{ strcpy(reason,"$$lim(x->-infinity,arccot x)=\\pi$$");
*next = pi_term;
}
else if(f == ROOT && equals(u,minusinfinity) && isodd(ARG(0,t)))
{ *next = minusinfinity;
strcpy(reason,"$lim(x\\to -\\infty ,root(n,x)) = -\\infty $ ");
strcat(reason, english(2240)); /* (n odd) */
}
else
{ *next = undefined;
strcpy(reason, english(849)); /* undefined limit */
}
HIGHLIGHT(*next);
return 0;
}
/* Now f==LIMIT */
u = LIMITAND(t);
f = FUNCTOR(u);
if(f != g)
return 1;
v = (f==ROOT ? ARG(1,u) : ARG(0,u));
mid = ARITY(t)==2 ? limit(ARG(0,t),v) : limit3(ARG(0,t),ARG(1,t),v);
err = limval(mid,&ans);
if(err)
return 1;
if(!NOTDEFINED(ans))
return 1;
if(equals(ans,minusinfinity))
{ switch(g)
{ case ATAN:
strcpy(reason,"$$lim(x->-infinity,arctan x)=-pi/2$$");
*next = tnegate(make_fraction(pi_term,two));
HIGHLIGHT(*next);
return 0;
case ACOT:
strcpy(reason,"$$lim(x->-infinity,arccot x)=\\pi$$");
*next = pi_term;
HIGHLIGHT(*next);
return 0;
case TANH:
strcpy(reason,"$$lim(x->-infinity,tanh x) = -1$$");
*next = minusone;
HIGHLIGHT(*next);
return 0;
case ROOT:
if(isodd(ARG(0,u)))
{ *next = minusinfinity;
HIGHLIGHT(*next);
strcpy(reason,"$lim(x\\to-\\infty ,root(n,x)) = -\\infty $ ");
strcat(reason, english(2240)); /* (n odd) */
return 0;
}
break;
}
return 1;
}
if(equals(ans,infinity))
{ switch(g)
{ case LN:
strcpy(reason, "$$lim(t->infinity,ln t) = infinity$$");
*next = infinity;
break;
case SQRT:
strcpy(reason, "$$lim(t->infinity,sqrt t) = infinity$$");
*next = infinity;
break;
case ROOT:
strcpy(reason, "$$lim(t->infinity,root(n,t) = infinity$$");
*next = infinity;
break;
case ATAN:
strcpy(reason,"$$lim(x->infinity,arctan x) = pi/2$$");
*next = make_fraction(pi_term,two);
break;
case TANH:
strcpy(reason,"$$lim(x->infinity,tanh x) = 1$$");
*next = one;
break;
default:
return 1;
}
HIGHLIGHT(*next);
return 0;
}
if(NOTDEFINED(ans))
{ *next = ans;
HIGHLIGHT(*next);
strcpy(reason, english(1371)); /* f(undefined) = undefined */
return 0;
}
return 1;
}
/*___________________________________________________________________*/
int limthruexp(term t, term arg, term *next, char *reason)
/* "lim(e^u) = e^(lim u)"*/
/* in automode, used only for undefined limits that can't be done by limval */
{ term u,x,base,power;
if(FUNCTOR(t) != LIMIT)
return 1;
u = LIMITAND(t);
x = ARG(0,ARG(0,t)); /* the limit variable */
if(FUNCTOR(u) != '^')
return 1;
base = ARG(0,u);
if(depends(base,x))
return 1;
power = ARG(1,u);
*next = make_power(base,ARITY(t)==2 ? limit(ARG(0,t),power) : limit3(ARG(0,t),ARG(1,t),power));
strcpy(reason,"lim(e^u) = e^(lim u)"); /* change 2 lines below if you change this */
if(!equals(base,eulere))
reason[4] = reason[11] = 'c';
HIGHLIGHT(*next);
return 0;
}
/*___________________________________________________________________*/
int limthrulog(term t, term arg, term *next, char *reason)
/* lim(ln u) = ln(lim u)*/
/* in automode, used only for undefined limits that can't be done by limval */
{ term u,v;
if(FUNCTOR(t) != LIMIT)
return 1;
u = LIMITAND(t);
if(FUNCTOR(u) != LN)
return 1;
v = ARG(0,u);
*next = ARITY(t)==2 ? ln1(limit(ARG(0,t),v)) : ln1(limit3(ARG(0,t),ARG(1,t),v));
strcpy(reason,"lim(ln u) = ln(lim u)");
HIGHLIGHT(*next);
return 0;
}
/*___________________________________________________________________*/
int limthrusin(term t, term arg, term *next, char *reason)
/* lim(sin u) = sin(lim u)*/
{ term u,v;
if(FUNCTOR(t) != LIMIT)
return 1;
u = LIMITAND(t);
if(FUNCTOR(u) != SIN)
return 1;
v = ARG(0,u);
*next = ARITY(t)==2 ? sin1(limit(ARG(0,t),v)) : sin1(limit3(ARG(0,t),ARG(1,t),v));
strcpy(reason,"lim(sin u) = sin(lim u)");
HIGHLIGHT(*next);
return 0;
}
/*___________________________________________________________________*/
int limthrucos(term t, term arg, term *next, char *reason)
/* lim(sin u) = sin(lim u)*/
{ term u,v;
if(FUNCTOR(t) != LIMIT)
return 1;
u = LIMITAND(t);
if(FUNCTOR(u) != COS)
return 1;
v = ARG(0,u);
*next = ARITY(t)==2 ? cos1(limit(ARG(0,t),v)) : cos1(limit3(ARG(0,t),ARG(1,t),v));
strcpy(reason,"lim(cos u) = cos(lim u)");
HIGHLIGHT(*next);
return 0;
}
/*_____________________________________________________________________*/
int timesinfinity(term t, term arg, term *next, char *reason)
/* lim uv when lim u = \\infty and lim v # 0 */
/* That is, \\infty \cdot nonzero = \\infty */
{ unsigned short n;
int i,err;
term u;
int flagleft,flagright,flagundef;
if(FUNCTOR(t) != '*')
return 1;
n = ARITY(t);
flagleft = flagright = flagundef = 0;
for(i=0;i<n;i++)
{ u = ARG(i,t);
if(equals(u,infinity))
++flagright;
else if (equals(u,minusinfinity))
++flagleft;
else if (WILD(u))
++flagundef;
}
if(flagleft == 0 && flagright == 0 && flagundef == 0)
return 1;
if(flagundef)
{ *next = undefined;
HIGHLIGHT(*next);
strcpy(reason, english(967)); /* undefined factor */
}
if((flagleft || flagright) && contains(t,LIMIT))
{ errbuf(0, english(850));
/* "First evaluate the other limits in the product. */
return 1;
}
if(flagleft & 1) /* odd number of minus infinities */
{ *next = minusinfinity;
strcpy(reason, english(968));
/* lim uv = -\\infty if u\\to -\\infty and lim v # 0 */
}
else if(flagright || flagleft)
{ *next = infinity;
strcpy(reason, english(969));
/* lim uv = \\infty if u\\to \\infty and lim v # 0 */
}
else
return 1;
/* We still must make sure the other factors aren't zero */
for(i=0;i<n;i++)
{ u = ARG(i,t);
if(!NOTDEFINED(u))
{ err = infer(nonzero(u));
if(err)
{ errbuf(0, english(851));
/* Can't verify other factors are nonzero. */
return 1;
}
}
}
HIGHLIGHT(*next);
return 0;
}
/*_____________________________________________________________________*/
int infinitytimesinfinity(term t, term arg, term *next, char *reason)
/* \\infty \times \\infty = \\infty */
{ unsigned short n;
int i,err;
term u;
int flagleft,flagright,flagundef;
if(FUNCTOR(t) != '*')
return 1;
n = ARITY(t);
flagleft = flagright = flagundef = 0;
for(i=0;i<n;i++)
{ u = ARG(i,t);
if(equals(u,infinity))
++flagright;
else if (equals(u,minusinfinity))
++flagleft;
else if (WILD(u))
++flagundef;
}
if(flagleft == 0 && flagright == 0 && flagundef == 0)
return 1;
if(flagundef)
{ *next = undefined;
HIGHLIGHT(*next);
strcpy(reason, english(967)); /* undefined factor */
}
if((flagleft || flagright) && contains(t,LIMIT))
{ errbuf(0, english(850));
/* First evaluate the other limits in the product. */
return 1;
}
if(flagleft & 1) /* odd number of minus infinities */
*next = minusinfinity;
else if(flagright + flagleft > 1)
*next = infinity;
else
return 1;
/* We still must make sure the other factors aren't zero */
for(i=0;i<n;i++)
{ u = ARG(i,t);
if(!NOTDEFINED(u))
{ err = infer(nonzero(u));
if(err)
{ errbuf(0, english(851));
/* Can't verify other factors are nonzero. */
return 1;
}
}
}
HIGHLIGHT(*next);
strcpy(reason, "$\\infty \\times \\infty = \\infty $");
return 0;
}
/*_____________________________________________________________________*/
int addinfinity(term t, term arg, term *next, char *reason)
/* lim u+v when lim u = \pm \\infty and lim v # \pm \\infty */
/* That is, \\infty + finite = \\infty */
{ unsigned short n;
int i,err;
term u;
int flagleft,flagright,flagundef;
if(FUNCTOR(t) != '+')
return 1;
if(contains_calc(t))
return 1; /* no integrals or limits allowed */
n = ARITY(t);
flagleft = flagright = flagundef = 0;
for(i=0;i<n;i++)
{ u = ARG(i,t);
if(equals(u,infinity))
++flagright;
else if (equals(u,minusinfinity))
++flagleft;
else if (WILD(u))
++flagundef;
else if(FUNCTOR(u) == '*' && POSNUMBER(ARG(0,u)) && ARITY(u) == 2 && equals(ARG(1,u),infinity))
++flagright; /* accept 2 infinity for example as infinite */
else if(NEGATIVE(u) && FUNCTOR(ARG(0,u)) == '*' && ARITY(ARG(0,u)) == 2 &&
POSNUMBER(ARG(0,ARG(0,u))) && equals(ARG(1,ARG(0,u)),infinity)
)
++flagleft; /* accept -2 infinity as minus infinity */
else if(FUNCTOR(u) == '^' && INTEGERP(ARG(1,u)) && equals(ARG(0,u),infinity))
++flagright; /* accept infinity^3 as infinite */
else if(NEGATIVE(u) && FUNCTOR(ARG(0,u)) == '^' && equals(ARG(0,ARG(0,u)),infinity)
&& POSNUMBER(ARG(1,ARG(0,u)))
)
++flagleft;
else if(contains(u,INFINITYFUNCTOR) || contains(u,BOUNDED_OSCILLATIONS) ||
contains(u,UNBOUNDED_OSCILLATIONS) || contains(u,UNDEFINED)
)
return 1;
}
if(flagleft == 0 && flagright == 0 && flagundef == 0)
return 1;
if(flagleft && flagright)
{ errbuf(0, english(852));
/* "You have reached an indeterminate form. */
errbuf(1, english(853));
/* Undo back to where these terms were created. */
return 1;
}
if(flagundef)
{ *next = undefined;
HIGHLIGHT(*next);
strcpy(reason, english(970)); /* undefined summand */
}
if((flagleft || flagright) && contains(t,LIMIT))
{ errbuf(0, english(854));
/* First evaluate the other limits in the sum. */
return 1;
}
if(flagleft)
{ *next = minusinfinity;
strcpy(reason, english(971));
/* lim u+v = -\\infty if u\\to -\\infty and lim v #0 */
}
else if(flagright)
{ *next = infinity;
strcpy(reason, english(972));
/* lim u+v = \\infty if u\\to \\infty and lim v finite */
}
else
return 1;
/* We still must make sure the other factors are defined */
for(i=0;i<n;i++)
{ u = ARG(i,t);
if(!NOTDEFINED(u))
{ err = infer(domain(u));
if(err)
{ errbuf(0, english(855));
/* Can't verify that the other summands are defined. */
return 1;
}
}
}
HIGHLIGHT(*next);
return 0;
}
/*_____________________________________________________________________*/
int infinityplusinfinity(term t, term arg, term *next, char *reason)
/* \\infty + \\infty = \\infty */
{ unsigned short n;
int i,err;
term u;
int problemtype;
int flagleft,flagright,flagundef;
if(FUNCTOR(t) != '+')
return 1;
n = ARITY(t);
flagleft = flagright = flagundef = 0;
for(i=0;i<n;i++)
{ u = ARG(i,t);
if(equals(u,infinity))
++flagright;
else if (equals(u,minusinfinity))
++flagleft;
else if (WILD(u))
++flagundef;
}
if(flagleft == 0 && flagright == 0 && flagundef == 0)
return 1;
if(flagleft && flagright)
{ errbuf(0, english(852));
/* "You have reached an indeterminate form. */
problemtype = get_problemtype();
if(problemtype == LHOPITAL || problemtype == LIMITS)
errbuf(1, english(853));
/* Undo back to where these terms were created. */
return 1;
}
if(flagundef)
{ *next = undefined;
HIGHLIGHT(*next);
strcpy(reason, english(970)); /* undefined summand */
}
if((flagleft || flagright) && contains(t,LIMIT))
{ errbuf(0, english(854));
/* First evaluate the other limits in the sum. */
return 1;
}
if(flagleft > 1)
*next = minusinfinity;
else if(flagright > 1)
*next = infinity;
else
return 1;
/* We still must make sure the other factors are defined */
for(i=0;i<n;i++)
{ u = ARG(i,t);
if(!NOTDEFINED(u))
{ err = infer(domain(u));
if(err)
{ errbuf(0, english(855));
/* Can't verify that the other summands are defined. */
return 1;
}
}
}
HIGHLIGHT(*next);
strcpy(reason, "$\\infty + \\infty = \\infty $");
return 0;
}
/*_____________________________________________________________________*/
int infinityminusinfinity(term t, term arg, term *next, char *reason)
/* \\infty + \\infty = \\infty */
{ unsigned short n;
int i;
term u;
int flagleft,flagright,flagundef;
if(FUNCTOR(t) != '+')
return 1;
n = ARITY(t);
flagleft = flagright = flagundef = 0;
for(i=0;i<n;i++)
{ u = ARG(i,t);
if(equals(u,infinity))
++flagright;
else if (equals(u,minusinfinity))
++flagleft;
else if (WILD(u))
++flagundef;
}
if(flagleft == 0 && flagright == 0 && flagundef == 0)
return 1;
if(flagleft && flagright)
{ *next = undefined;
HIGHLIGHT(*next);
strcpy(reason, "$\\infty - \\infty = undefined$");
return 0;
}
return 1;
}
/*_____________________________________________________________________*/
int infinityovernonzero(term t, term arg, term *next, char *reason)
{ term num,den;
int sign;
if(FUNCTOR(t) != '/')
return 1;
num = ARG(0,t);
den = ARG(1,t);
if(NOTDEFINED(den))
{ errbuf(0, english(856));
/* denominator must be defined and nonzero. */
return 1;
}
if(!NOTDEFINED(num))
return 1;
if(contains(den,LIMIT))
{ errbuf(0, english(1958));
/* First evaluate the limit. */
return 1;
}
sign = get_sign(den);
if(sign == 0)
{ errbuf(0, english(857));
/* denominator must be nonzero */
return 1;
}
if(WILD(num) || sign > 0)
*next = num;
else if(sign < 0)
tneg(num,next);
HIGHLIGHT(*next);
strcpy(reason, english(859));
/* lim(u/v) = lim u if lim v \\ne 0, lim u = \pm \\infty */
return 0;
}
/*_____________________________________________________________________*/
int nonzerooverinfinity(term t, term arg, term *next, char *reason)
{ term num,den;
int err;
if(FUNCTOR(t) != '/')
return 1;
num = ARG(0,t);
den = ARG(1,t);
if(NOTDEFINED(num))
{ errbuf(0, english(860));
/* numerator must be defined and nonzero. */
return 1;
}
if(!NOTDEFINED(den))
return 1;
err = check1(nonzero(num));
if(err)
{ errbuf(0, english(861));
/* numerator must be nonzero */
return 1;
}
if(WILD(den))
return 1; /* *next = undefined; */
else
*next = zero;
strcpy(reason, english(862));
/* "lim(u/v) = 0 if lim u \\ne 0, lim v = \pm \\infty */
return 0;
}
/*_____________________________________________________________________*/
int zerodenom3(term t, term arg, term *next, char *reason)
{ term num,denom;
if(FUNCTOR(t) != '/')
return 1;
denom = ARG(1,t);
num = ARG(0,t);
if(!ISZERO(denom))
return 1;
if(NOTDEFINED(num))
{ errbuf(0, english(863));
/* numerator must be defined and nonzero. */
return 1;
}
if(contains(num,LIMIT))
{ errbuf(0, english(864));
/* First evaluate the numerator */
return 1;
}
if(!POSITIVE_INFINITESIMAL(t) && !NEGATIVE_INFINITESIMAL(t))
{ *next = undefined;
strcpy(reason,english(938)); /* a/0 = undefined */
/* no point trying to find the sign of the numerator */
HIGHLIGHT(*next);
return 0;
}
return 1;
}
/*_____________________________________________________________________*/
int zerodenom(term t, term arg, term *next, char *reason)
{ term num,denom;
int err;
if(!FRACTION(t))
return 1;
num = ARG(0,t);
denom = ARG(1,t);
if(!ISZERO(denom))
return 1;
if(NOTDEFINED(num))
{ errbuf(0, english(863));
/* numerator must be defined and nonzero. */
return 1;
}
if(contains(num,LIMIT))
{ errbuf(0, english(864));
/* First evaluate the numerator */
return 1;
}
if(!POSITIVE_INFINITESIMAL(t))
return 1;
err = infer(lessthan(zero,num));
if(!err)
{ *next = infinity;
strcpy(reason, english(939)); /* a/0+ = \\infty if a>0 */
HIGHLIGHT(*next);
release(polyvalop);
release(arithmetic);
return 0;
}
err = infer(lessthan(num,zero));
if(!err)
{ *next = minusinfinity;
strcpy(reason, english(941)); /* a/0+ = -\\infty if a<0 */
HIGHLIGHT(*next);
release(polyvalop);
release(arithmetic);
return 0;
}
*next = undefined;
strcpy(reason, english(938));
HIGHLIGHT(*next);
commentbuf(0,english(865));
/* Can't determine sign of numerator */
release(polyvalop);
return 0;
}
/*_____________________________________________________________________*/
int zerodenom2(term t, term arg, term *next, char *reason)
{ term num,denom;
int err;
if(!FRACTION(t))
return 1;
denom = ARG(1,t);
num = ARG(0,t);
if(!ISZERO(denom))
return 1;
if(NOTDEFINED(num))
{ errbuf(0, english(863));
/* numerator must be defined and nonzero. */
return 1;
}
if(contains(num,LIMIT))
{ errbuf(0, english(864));
/* First evaluate the numerator */
return 1;
}
if(!NEGATIVE_INFINITESIMAL(t))
return 1;
err = infer(lessthan(zero,num));
if(!err)
{ *next = minusinfinity;
strcpy(reason, english(940)); /* a/0- = -\\infty if a>0 */
HIGHLIGHT(*next);
release(polyvalop);
release(arithmetic);
return 0;
}
err = infer(lessthan(num,zero));
if(!err)
{ *next = infinity;
strcpy(reason, english(942)); /* a/0- = \\infty if a<0 */
HIGHLIGHT(*next);
release(polyvalop);
return 0;
}
*next = undefined;
strcpy(reason, english(938));
HIGHLIGHT(*next);
commentbuf(0,english(865));
/* Can't determine sign of numerator */
release(polyvalop);
return 0;
}
/*_____________________________________________________________________*/
int infinityoverzero(term t, term arg, term *next, char *reason)
{ term num, denom;
if(FUNCTOR(t) != '/')
return 1;
num = ARG(0,t);
denom = ARG(1,t);
if(!ISZERO(denom))
return 1;
if(equals(num,infinity) && POSITIVE_INFINITESIMAL(t))
{ *next = infinity;
HIGHLIGHT(*next);
strcpy(reason,"$\\infty /0+ = \\infty $");
return 0;
}
return 1;
}
/*_____________________________________________________________________*/
int infinityoverzerosq(term t, term arg, term *next, char *reason)
{ term num, denom;
if(FUNCTOR(t) != '/')
return 1;
num = ARG(0,t);
denom = ARG(1,t);
if(FUNCTOR(denom)!= '^')
return 1;
if(!equals(ARG(1,denom),two))
return 1;
if(!ZERO(ARG(0,denom)))
return 1;
if(equals(num,infinity))
{ *next = infinity;
HIGHLIGHT(*next);
strcpy(reason,"$\\infty /0^2 = \\infty $");
return 0;
}
return 1;
}
/*_____________________________________________________________________*/
int infinityoverzero2n(term t, term arg, term *next, char *reason)
{ term num, denom;
if(FUNCTOR(t) != '/')
return 1;
num = ARG(0,t);
denom = ARG(1,t);
if(FUNCTOR(denom)!= '^')
return 1;
if(!iseven(ARG(1,denom)))
return 1;
if(!ZERO(ARG(0,denom)))
return 1;
if(equals(num,infinity))
{ *next = infinity;
HIGHLIGHT(*next);
strcpy(reason,"$\\infty /0^(2n) = \\infty $");
return 0;
}
return 1;
}
/*_____________________________________________________________________*/
int infinityoverzero2(term t, term arg, term *next, char *reason)
{ term num, denom;
if(FUNCTOR(t) != '/')
return 1;
num = ARG(0,t);
denom = ARG(1,t);
if(!ISZERO(denom))
return 1;
if(equals(num,infinity) && NEGATIVE_INFINITESIMAL(t))
{ *next = minusinfinity;
HIGHLIGHT(*next);
strcpy(reason,"$\\infty /0- = -\\infty $");
return 0;
}
return 1;
}
/*_____________________________________________________________________*/
int infinityoverzero3(term t, term arg, term *next, char *reason)
{ term num, denom;
if(FUNCTOR(t) != '/')
return 1;
num = ARG(0,t);
denom = ARG(1,t);
if(!ISZERO(denom))
return 1;
if(equals(num,infinity) &&
!NEGATIVE_INFINITESIMAL(t) &&
!POSITIVE_INFINITESIMAL(t)
)
{ *next = undefined;
HIGHLIGHT(*next);
strcpy(reason,"$\\infty /0$ = undefined");
commentbuf(0,english(858));
/* !Sign of denominator unknown */
return 0;
}
return 1;
}
/*_____________________________________________________________________*/
int toinfinity1(term t, term arg, term *next, char *reason)
/* u^\\infty = \\infty if u > 1 */
{ term u;
int err;
if(FUNCTOR(t) != '^')
return 1;
u = ARG(0,t);
if(!equals(ARG(1,t),infinity))
return 1;
if(NOTDEFINED(u))
return 1;
err = infer(lessthan(one,u));
if(err)
{ errbuf(0, english(866));
/* base must exceed 1 */
return 1;
}
*next = infinity;
HIGHLIGHT(*next);
strcpy(reason,"$u^\\infty = \\infty (u > 1)$");
return 0;
}
/*_____________________________________________________________________*/
int toinfinity0(term t, term arg, term *next, char *reason)
/* u^\\infty = 0 if 0 < u < 1 */
{ term u;
int err;
if(FUNCTOR(t) != '^')
return 1;
u = ARG(0,t);
if(!equals(ARG(1,t),infinity))
return 1;
if(NOTDEFINED(u))
return 1;
err = infer(lessthan(zero,u));
if(err)
{ errbuf(0, english(867));
/* Base must be positive */
return 1;
}
err = infer(lessthan(u,one));
if(err)
{ errbuf(0, english(868));
/* Base must be less than 1 */
return 1;
}
*next = zero;
HIGHLIGHT(*next);
strcpy(reason, english(958)); /* u^\\infty = 0 if 0 < u < 1 */
return 0;
}
/*_____________________________________________________________________*/
int tominusinfinity1(term t, term arg, term *next, char *reason)
/* "u^(-\\infty ) = 0 (u > 1)", */
{ term u;
int err;
if(FUNCTOR(t) != '^')
return 1;
u = ARG(0,t);
if(!equals(ARG(1,t),minusinfinity))
return 1;
if(NOTDEFINED(u))
return 1;
err = infer(lessthan(one,u));
if(err)
{ errbuf(0, english(869));
/* Base must exceed 1 */
return 1;
}
*next = zero;
HIGHLIGHT(*next);
strcpy(reason, english(973)); /* u^(-\\infty ) = 0 if u > 1 */
return 0;
}
/*_____________________________________________________________________*/
int tominusinfinity0(term t, term arg, term *next, char *reason)
/* "u^(-\\infty ) = \\infty (0<u<1)", */
{ term u;
int err;
if(FUNCTOR(t) != '^')
return 1;
u = ARG(0,t);
if(!equals(ARG(1,t),minusinfinity))
return 1;
if(NOTDEFINED(u))
return 1;
err = infer(lessthan(zero,u));
if(err)
{ errbuf(0, english(867));
/* Base must be positive */
return 1;
}
err = infer(lessthan(u,one));
if(err)
{ errbuf(0, english(868));
/* Base must be less than 1 */
return 1;
}
*next = infinity;
HIGHLIGHT(*next);
strcpy(reason, english(974)); /* u^(-\\infty ) = \\infty if 0<u<1 */
return 0;
}
/*_____________________________________________________________________*/
int lninfinity(term t, term arg, term *next, char *reason)
{ term u;
if(FUNCTOR(t)!= LN && FUNCTOR(t) != LOG)
return 1;
u = ARG(0,t);
if(!equals(u,infinity))
return 1;
*next = infinity;
strcpy(reason, "$lim(x\\to \\infty ,ln x) = \\infty $");
HIGHLIGHT(*next);
return 0;
}
/*_____________________________________________________________________*/
int lnzero(term t, term arg, term *next, char *reason)
/* ln 0 = -infinity */
{ term u;
if(FUNCTOR(t)!= LN && FUNCTOR(t) != LOG)
return 1;
u = ARG(0,t);
if(!ZERO(u))
return 1;
*next = minusinfinity;
strcpy(reason, "$lim(x\\to 0+,ln x) = -\\infty $");
HIGHLIGHT(*next);
return 0;
}
/*_____________________________________________________________________*/
int sqrtinfinity(term t, term arg, term *next, char *reason)
{ term u;
if(FUNCTOR(t)!= SQRT)
return 1;
u = ARG(0,t);
if(!equals(u,infinity))
return 1;
*next = infinity;
strcpy(reason, english(957)); /* \sqrt x\to \\infty as x\to \\infty */
HIGHLIGHT(*next);
return 0;
}
/*_____________________________________________________________________*/
int rootinfinity(term t, term arg, term *next, char *reason)
{ term u,index;
int err;
if(FUNCTOR(t)!= ROOT)
return 1;
u = ARG(1,t);
index = ARG(0,t);
if(!NOTDEFINED(u))
return 1;
if(equals(u,infinity))
{ *next = infinity;
strcpy(reason, english(956)); /* root(n,x)\to \\infty as x\to \\infty */
HIGHLIGHT(*next);
return 0;
}
err = infer(odd(index));
if(!err)
{ *next = minusinfinity;
strcpy(reason, english(955)); /* root(n,x)\to -\\infty as x\to -\\infty , n odd */
HIGHLIGHT(*next);
return 0;
}
*next = undefined;
HIGHLIGHT(*next);
strcpy(reason, english(954)); /* n not odd in ^n\sqrt */
return 0;
}
/*_____________________________________________________________________*/
int powerofinfinity(term t, term arg, term *next, char *reason)
/* infinity ^n = infinity if n > 0 */
{ term u;
int err;
if(FUNCTOR(t)!= '^')
return 1;
u = ARG(0,t);
if(!equals(u,infinity))
return 1;
err = infer(lessthan(zero,ARG(1,t)));
if(err)
return 1;
*next = infinity;
strcpy(reason, english(1116)); /* x^n\to \\infty as x\to \\infty if n>0 */
HIGHLIGHT(*next);
return 0;
}
/*_____________________________________________________________________*/
int ataninfinity(term t, term arg, term *next, char *reason)
{ term u;
if(FUNCTOR(t)!= ATAN)
return 1;
u = ARG(0,t);
if(!NOTDEFINED(u))
return 1;
if(equals(u,infinity))
{ *next = make_fraction(pi_term,two);
strcpy(reason, "$$lim(x->infinity,arctan x)=\\pi/2$$");
}
else if(equals(u,minusinfinity))
{ *next = tnegate(make_fraction(pi_term,two));
strcpy(reason, "$$lim(x->infinity,arctan x) = -pi/2$$");
}
else
return 1;
HIGHLIGHT(*next);
return 0;
}
/*_____________________________________________________________________*/
int acotinfinity(term t, term arg, term *next, char *reason)
{ term u;
if(FUNCTOR(t)!= ACOT)
return 1;
u = ARG(0,t);
if(!NOTDEFINED(u))
return 1;
if(!equals(u,infinity))
return 1;
*next = zero;
strcpy(reason, "$lim(x\\to \\infty ,arccot x)=0$");
HIGHLIGHT(*next);
return 0;
}
/*_____________________________________________________________________*/
int acotminusinfinity(term t, term arg, term *next, char *reason)
{ term u;
if(FUNCTOR(t)!= ACOT)
return 1;
u = ARG(0,t);
if(!NOTDEFINED(u))
return 1;
if(!equals(u,minusinfinity))
return 1;
*next = pi_term;
strcpy(reason, "$$lim(x->-infinity,arccot x)=\\pi$$");
HIGHLIGHT(*next);
return 0;
}
/*_____________________________________________________________________*/
int asecinfinity(term t, term arg, term *next, char *reason)
{ term u;
if(FUNCTOR(t)!= ASEC)
return 1;
u = ARG(0,t);
if(!ISINFINITE(u))
return 1;
*next = make_fraction(pi_term,two);
strcpy(reason, "$$lim(x->infinity,arcsec x)=\\pi/2$$");
HIGHLIGHT(*next);
return 0;
}
/*_____________________________________________________________________*/
int acscinfinity(term t, term arg, term *next, char *reason)
{ term u;
if(FUNCTOR(t)!= ACSC)
return 1;
u = ARG(0,t);
if(!ISINFINITE(u))
return 1;
*next = zero;
if(NEGATIVE(u))
strcpy(reason, "$$lim(x->-infinity,arccsc x)=0$$");
else
strcpy(reason, "$$lim(x->infinity,arccsc x)=0$$");
HIGHLIGHT(*next);
return 0;
}
/*_____________________________________________________________________*/
int triginfinity(term t, term arg, term *next, char *reason)
{ term u;
char buffer[12];
unsigned short f = FUNCTOR(t);
if(f==SIN || f==COS)
{ u = ARG(0,t);
if (equals(u,infinity) || equals(u,minusinfinity))
*next = bounded_oscillations;
else
return 1;
}
else if(f==TAN || f == SEC || f == CSC || f == COT)
{ u = ARG(0,t);
if (equals(u,infinity) || equals(u,minusinfinity))
*next = unbounded_oscillations;
else
return 1;
}
else
return 1;
functor_string(f,SCREEN,buffer);
strcpy(reason,"$lim(x\\to\\infty ,$");
strcat(reason, buffer);
strcat(reason,"( x ) ");
strcat(reason, english(2181)); /* is undefined */
HIGHLIGHT(*next);
return 0;
}
/*_____________________________________________________________________*/
int coshinfinity(term t, term arg, term *next, char *reason)
{ term u;
if(FUNCTOR(t)!= COSH)
return 1;
u = ARG(0,t);
if(!ISINFINITE(u))
return 1;
*next = infinity;
if(NEGATIVE(u))
strcpy(reason, "$$lim(x->-infinity,cosh x)=infinity$$");
else
strcpy(reason, "$$lim(x->infinity,cosh x)=infinity$$");
HIGHLIGHT(*next);
return 0;
}
/*_____________________________________________________________________*/
int sinhinfinity(term t, term arg, term *next, char *reason)
{ term u;
if(FUNCTOR(t)!= SINH)
return 1;
u = ARG(0,t);
if(!ISINFINITE(u))
return 1;
if(equals(u,infinity))
{ *next = infinity;
strcpy(reason, "$lim(x\\to\\infty ,sinh x) = \\infty $");
}
else /* u is minusinfinity */
{ *next = minusinfinity;
strcpy(reason, "$lim(x\\to-\\infty ,sinh x)=-\\infty $");
}
HIGHLIGHT(*next);
return 0;
}
/*_____________________________________________________________________*/
int tanhinfinity(term t, term arg, term *next, char *reason)
{ term u;
if(FUNCTOR(t)!= TANH)
return 1;
u = ARG(0,t);
if(!ISINFINITE(u))
return 1;
if(equals(u,infinity))
{ *next = one;
strcpy(reason, "$lim(x\\to\\infty ,sinh x) = 1$");
}
else /* u is minusinfinity */
{ *next = minusone;
strcpy(reason, "$lim(x\\to-\\infty ,sinh x)=-1$");
}
HIGHLIGHT(*next);
return 0;
}
/*______________________________________________________________________*/
int rationalizesum(term t, term arg, term *next, char *reason)
/* Example: lim(x->-infinity, x + \sqrt (x^2-1)).
See rationalize_ok for other examples where we do and don't
want this used. */
{ term u,v,s;
int err;
if(FUNCTOR(t) != LIMIT)
return 1;
u = LIMITAND(t);
if(FUNCTOR(u) != '+')
return 1;
if(get_mathmode() == AUTOMODE && !rationalize_ok(t))
/* check for examples where this shouldn't be used, see above */
return 1;
v = make_term('/',2);
ARGREP(v,0,u);
ARGREP(v,1,one); /* construct v = u/1. You can't use make_fraction
as it discards denominators of 1 */
s = ARITY(t) == 2 ? limit(ARG(0,t),v) : limit3(ARG(0,t),ARG(1,t),v);
err = rationalizenum(s,arg,next,reason);
/* rationalizenum calls set_pathtail with the result that the
path to the sum is selected. */
if(err)
{ RELEASE(s);
return 1;
}
SetShowStepOperation(rationalizenum);
return 0;
}
/*______________________________________________________________________*/
int limleadingterms(term t, term arg, term *next, char *reason)
/* lim u/v = lim (leading-term(u)/leading-term(v)) */
{ term a,x,u,v,w,num,denom,c,deg,c2,deg2,newnum,newdenom;
int err,numflag=0,denomflag=0;
int n = ARITY(t);
if(FUNCTOR(t) != LIMIT)
return 1;
u = LIMITAND(t);
x = ARG(0,ARG(0,t));
a = ARG(1,ARG(0,t));
if(FRACTION(u))
{ num = ARG(0,u);
denom = ARG(1,u);
err = leading_term(num,x,a,&c,°);
if(err)
return 1;
err = leading_term(denom,x,a,&c2,°2);
if(err)
return 1;
err = infer(nonzero(c));
if(err)
return 1;
err = infer(nonzero(c2));
if(err)
return 1;
w = (ZERO(a) || ISINFINITE(a)) ? x : sum(x,tnegate(a));
newnum = ZERO(deg) ? c : signedproduct(c,make_power(w,deg));
newdenom = ZERO(deg2) ? c2: signedproduct(c2, make_power(w,deg2));
if(!equals(newdenom,denom))
{ HIGHLIGHT(newdenom);
denomflag = 1;
}
if(!equals(newnum,num))
{ HIGHLIGHT(newnum);
numflag = 1;
}
if(!numflag && !denomflag)
return 1;
v = make_fraction(newnum,newdenom);
*next = n==2 ? limit(ARG(0,t),v) : limit3(ARG(0,t),ARG(1,t),v);
strcpy(reason, english(1146));
/* use leading term */
if(numflag && denomflag)
{ commentbuf(0, english(1112));
/* lim((u+a)/(v+b))=lim(u/v) if a/u\\to 0 and b/v\\to 0 */
commentbuf(1, english(1149));
/* Here u and v are the leading terms of num and denom */
}
else if (numflag)
{ commentbuf(0, english(1113));
/* lim((u+a)/v) = lim(u/v) if a/u\\to 0 */
commentbuf(1, english(1147));
/* Here u is the leading term of the numerator. */
}
else
{ commentbuf(0, english(1114));
/* lim(u/(v+b)) = lim(u/v) if b/v\\to 0", */
commentbuf(1, english(1148));
/* Here v is the leading term of the denominator */
}
return 0;
}
return 1;
}
/*______________________________________________________________________*/
int limleadingterm(term t, term arg, term *next, char *reason)
/* lim(u+a)=lim(u) if a/u\\to 0 */
{ term a,x,u,v,w,c,deg;
int err;
int n = ARITY(t);
if(FUNCTOR(t) != LIMIT)
return 1;
u = LIMITAND(t);
x = ARG(0,ARG(0,t));
a = ARG(1,ARG(0,t));
if(FRACTION(u))
{ errbuf(0, english(1393));
/* There is a similar operation that works on fractions */
return 1;
}
/* Now it's not a fraction */
err = leading_term(u,x,a,&c,°);
if(err && get_mathmode() == AUTOMODE)
return 1;
w = (ZERO(a) || ISINFINITE(a)) ? x : sum(x,tnegate(a));
if(ZERO(deg))
return 1;
v = product(c, ONE(deg)? w : make_power(w,deg));
if(equals(v,u))
return 1;
HIGHLIGHT(v);
*next = n==2 ? limit(ARG(0,t),v) : limit3(ARG(0,t),ARG(1,t),v);
strcpy(reason, english(1115));
/* lim(u+a)=lim(u) if a/u\\to 0 */
return 0;
}
/*______________________________________________________________________*/
static int slt_aux(term u, term x, term *ans, char *reason)
/* examine subterms of u, stopping if any functor
except /, *, ^, SQRT, and ROOT is encountered, and also
stopping at '^' if the exponent depends on x.
Look for a sum to which to apply sumleadingterm.
If found, substitute the
result for that sum and return it in *ans. Return 0 for
success, 1 for failure. Don't go into exponents, because of
examples like e^(x^2/(1-x)) e^-(x^2/(1+x)); if you apply
sumleading term to the 1-x and 1+x, you will get the wrong answer.
See ok_leadingterm in selectop.c for more examples.
*/
{ int i,j,err;
unsigned short n,f;
term temp;
f = FUNCTOR(u);
if(ATOMIC(u))
return 1;
if(f == '+')
return sumleadingterm(u,zero,ans,reason);
if(f != '*' && f != '/' && f != ROOT && f != SQRT && f != '^')
return 1;
if(f == '^') /* don't use it in the exponent, only in the base */
{ if(depends(ARG(1,u),x))
{ errbuf(0, english(1513));
/* Can't use leading terms because exponent is not constant. */
return 1;
}
err = slt_aux(ARG(0,u),x,&temp,reason);
if(err)
return 1;
*ans = make_power(temp,ARG(1,u));
return 0;
}
n = ARITY(u);
for(i=0;i<n;i++)
{ err = slt_aux(ARG(i,u),x,&temp,reason);
if(!err)
break;
}
if(i == n)
return 1;
*ans = make_term(f,n);
for(j=0;j<n;j++)
ARGREP(*ans,j, i==j ? temp : ARG(j,u));
return 0;
}
/*______________________________________________________________________*/
static int use_comdenom_instead(term x, term a, term s)
/* s is a sum, and lim(x->a,s) can be done by sumleadingterm, but
if we would rather not do so, but use commondenomandsimp instead
(presumably to be followed by L'Hopital's rule) then return 1.
Else return 0.
Example: lim(x->1, 1/ln(x) + 1/(x-1))
It's better to show a longer solution, except in case the leading
terms of each summand are obvious and they don't cancel out.
*/
{ term c,deg;
int err;
if(FUNCTOR(s) != '+')
return 0; /* assert(0) */
err = lt_plus(ARGPTR(s),ARITY(s),x,a,&c,°);
if(err)
return 0; /* this shouldn't happen, since sumleadingterm does work. */
if(ZERO(c)) /* the leading terms of the summands do cancel out */
return 1;
return 0;
}
/*______________________________________________________________________*/
int sumleadingterm(term u, term arg, term *next, char *reason)
/* replace a sum u by its leading term, provided
u occurs inside a limit, and the path from the LIMIT to u does
not include any sums. Indeed it should include only products,
quotients, roots, sqrts, and constant powers.
Example: in lim (x->infinity, x^2/(x-1) - x^2/(x+1)) you will
get the incorrect answer 0 if you apply this operation to the
sums in the denominator. See ok_sumleadingterm in selectops.c
for discussion of when this operation can be used.
In automode the operation is applied only to limit terms,
rather than directly to sums, as it is in term selection mode.
*/
{ term a,x,c,deg,dir,v,w,q,logdeg,s;
int err;
unsigned short path[MAXTAIL];
unsigned short n = ARITY(u);
if(get_mathmode() == MENUMODE && FUNCTOR(u) != LIMIT)
return 1;
if(FUNCTOR(u) == LIMIT)
/* menu mode or auto mode or term selection mode */
{ x = ARG(0,ARG(0,u)); /* the limit variable */
s = LIMITAND(u);
err = slt_aux(s,x,&v,reason);
if(err)
return 1;
/* in some cases it would be more instructive to use
common denoms followed by L'Hopital, e.g. lim(x->1, 1/ ln(x) + 1/(x-1)).
We can't control this from postops since in general we
don't want to use common denoms inside limits. So,
we do it here instead. */
a = ARG(1,ARG(0,u));
if(FUNCTOR(s) == '+' && use_comdenom_instead(x,a,s))
{ err = commondenomandsimp(s,zero,&v,reason);
*next = n==2 ? limit(ARG(0,u),v) : limit3(ARG(0,u),ARG(1,u),v);
SetShowStepOperation(commondenomandsimp);
path[0] = LIMIT;
path[1] = 2;
path[2] = 0;
set_pathtail(path);
return 0;
}
*next = n==2 ? limit(ARG(0,u),v) : limit3(ARG(0,u),ARG(1,u),v);
path_to_difference(u,*next,path,1);
set_pathtail(path);
return 0;
}
/* in term selection mode it's applied to sums.*/
if(FUNCTOR(u) != '+')
return 1;
/* Now we need to know the limit variable x and the limit point a
such that u is inside lim(x->a,...) */
err = get_limit_info(&x,&a,&dir);
if(err)
return 1; /* not inside a limit */
err = leading_term(u,x,a,&c,°);
if(!err)
{ if(ZERO(c))
return 1;
if(!ZERO(a) && !ISINFINITE(a))
x = sum(x,tnegate(a));
if(ZERO(deg))
*next = c;
else if(ONEHALF(deg) && contains(u,SQRT))
*next = product(c,sqrt1(x));
else if(ONE(deg))
*next = product(c,x);
else if(NEGATIVE(deg))
*next = make_fraction(c, make_power(x,ARG(0,deg)));
else
*next = product(c,make_power(x,deg));
goto succeed;
}
/* Don't give up, e.g. in sqrt(x + ln x) as x goes to infinity
we should be able to drop the ln x.
Also in sqrt(x) - sqrt(x) ln x we should be able to drop
the sqrt(x) term. */
err = log_leading_term(u,x,a,&c,°,&logdeg);
if(err)
return 1;
/* prepare the non-logarithmic part q first */
if(ZERO(c))
return 1;
if(!ZERO(a) && !ISINFINITE(a))
x = sum(x,tnegate(a));
if(ZERO(deg))
q = c;
else if(ONE(deg))
q = product(c,x);
else if(ONEHALF(deg) && contains(u,SQRT))
q = product(c,sqrt1(x));
else if(NEGATIVE(deg))
q = make_fraction(c, make_power(x,ARG(0,deg)));
else
q = product(c,make_power(x,deg));
if(ZERO(logdeg))
{ *next = q;
goto succeed;
}
if(NEGATIVE(logdeg))
{ w = make_power(ln1(x),ARG(0,logdeg));
if(FRACTION(q))
{ *next = make_fraction(ARG(0,q),product(ARG(1,q),w));
goto succeed;
}
*next = make_fraction(q,w);
goto succeed;
}
else
{ w = ONE(logdeg) ? ln1(x) : make_power(ln1(x),logdeg);
if(FRACTION(q))
{ *next = make_fraction(product(ARG(0,q),w),ARG(1,q));
goto succeed;
}
*next = product(q,w);
goto succeed;
}
succeed:
strcpy(reason, english(1512)); /* leading term */
HIGHLIGHT(*next);
return 0;
}
/*_____________________________________________________________*/
int rationalize_ok(term t)
/* t is a limit term with a limitand that is a sum or fraction.
Return 1 if it's a good idea to rationalize; that is, (for finite limits)
if some summand contains a sqrt (or root or abs) and the
whole limit is zero. Return 0 otherwise.
Remove any assumptions that are made during the calculations.
*/
/* We want rationalize_sum used on lim(x->-infinity,x+\sqrt (x^2-1)),
where the limit itself is not zero. But we
don't want to use rationalize_sum on lim(x->-infinity,x-\sqrt (x^2-1))
where both summands go to -infinity; we just want to use
limsum on that, otherwise we will loop. We only use it if the
limvals of the two summands are opposite.
At finite limits we just look for the limit to be zero. */
{ term u,a,c;
int err;
short savenextassumption = get_nextassumption();
term newlim;
unsigned short n = ARITY(t);
assert(FUNCTOR(t)==LIMIT);
u = LIMITAND(t);
if(FRACTION(u))
{ if(FUNCTOR(ARG(1,u)) == '+' && FUNCTOR(ARG(0,u)) != '+')
u = ARG(1,u);
else if(FUNCTOR(ARG(0,u)) == '+' && FUNCTOR(ARG(1,u)) != '+')
u = ARG(0,u);
else if(FUNCTOR(ARG(0,u)) == '+' && FUNCTOR(ARG(1,u)) == '+')
{ if(contains(ARG(1,u),SQRT) || contains(ARG(1,u),ROOT) || contains(ARG(1,u),ABSFUNCTOR))
u = ARG(1,u);
else
u = ARG(0,u);
}
else
return 0;
}
else if(!contains(u,SQRT) && !contains(u,ROOT) && !contains(u,ABSFUNCTOR))
return 0;
if(FUNCTOR(u) != '+')
return 0;
a = ARG(1,ARG(0,t));
if(NOTDEFINED(a))
{ if(ARITY(u) == 2)
{ /* just check that the limits are both infinite, but of
opposite signs */
term lim1 = n==2 ? limit(ARG(0,t),ARG(0,u)) : limit3(ARG(0,t),ARG(1,t),ARG(0,u));
term lim2 = n==2 ? limit(ARG(0,t),ARG(1,u)) : limit3(ARG(0,t),ARG(1,t),ARG(1,u));
term ans1, ans2;
err = limval(lim1, &ans1);
set_nextassumption(savenextassumption);
if(err || !NOTDEFINED(ans1))
return 0;
err = limval(lim2, &ans2);
set_nextassumption(savenextassumption);
if(err || !NOTDEFINED(ans2))
return 0;
return 1;
}
else
return 0;
}
/* Now at finite limits */
newlim = ARITY(t) == 2 ? limit(ARG(0,t),u) : limit3(ARG(0,t),ARG(1,t),u);
err= limval(newlim,&c);
set_nextassumption(savenextassumption);
if(err || !ZERO(c))
return 0;
return 1;
}
/*____________________________________________________*/
static int contains_undefined(term t)
/* return 1 if t contains UNDEFINED, BOUNDED_OSCILLATIONS, or
UNBOUNDED_OSCILLATIONS */
{ unsigned short n = ARITY(t);
int i;
unsigned short f = FUNCTOR(t);
if(OBJECT(t))
return 0;
if(n == 0 && (f == UNDEFINED || f == BOUNDED_OSCILLATIONS || f == UNBOUNDED_OSCILLATIONS))
return 1;
for(i=0;i<n;i++)
{ if(contains_undefined(ARG(i,t)))
return 1;
}
return 0;
}
/*____________________________________________________*/
int undefinedpart(term t, term arg, term *next, char *reason)
/* f(undefined) = undefined */
/* applied in automode to the whole current line */
{ if(equals(t,undefined))
return 1; /* don't cause a loop */
if(contains_undefined(t))
{ *next = undefined; /* losing info sometimes e.g. on 2*bounded_oscillations */
HIGHLIGHT(*next);
strcpy(reason,english(1371)); /* f(undefined)=undefined */
return 0;
}
return 1;
}
/*_____________________________________________________________________*/
int rationalizefraction(term t, term arg, term *next, char *reason)
/* called in auto mode instead of rationalizenum or rationalizedenom */
{ term num,denom;
int err;
if(FUNCTOR(t) != LIMIT)
return 1;
if(FUNCTOR(ARG(1,t)) != '/')
return 1;
if(get_mathmode() == AUTOMODE)
{ if(!rationalize_ok(t)) /* in inflims.c */
return 1;
}
num = ARG(0,ARG(1,t));
denom = ARG(1,ARG(1,t)); /* t = lim(h->a,num/denom) */
if(FUNCTOR(num) == '+' && ARITY(num)==2)
{ term b,c;
b = ARG(0,num);
c = ARG(1,num);
if( (grf_aux(b) || grf_aux(c) ) && /* square root or root or ABSFUNCTOR in one term */
(
(FUNCTOR(b) == '-' && FUNCTOR(c) != '-') || /* opposite signs */
(FUNCTOR(c) == '-' && FUNCTOR(b) != '-')
)
)
{ err = rationalizenum(t,arg,next,reason);
if(err)
return 1;
SetShowStepOperation(rationalizenum);
return 0;
}
}
if(FUNCTOR(denom) == '+' && ARITY(denom)==2)
{ term b,c;
b = ARG(0,denom);
c = ARG(1,denom);
if( (grf_aux(b) || grf_aux(c) ) && /* square root or root or ABSFUNCTOR in one term */
(
(FUNCTOR(b) == '-' && FUNCTOR(c) != '-') || /* opposite signs */
(FUNCTOR(c) == '-' && FUNCTOR(b) != '-')
)
)
{ err = rationalizedenom(t,arg,next,reason);
if(err)
return 1;
SetShowStepOperation(rationalizedenom);
return 0;
}
}
return 1;
}
/*_____________________________________________________________________*/
int zerosqdenom(term t, term arg, term *next, char *reason)
{ term num,denom;
int err;
if(FUNCTOR(t) != '/')
return 1;
num = ARG(0,t);
denom = ARG(1,t);
if(FUNCTOR(denom) != '^')
return 1;
if(!equals(ARG(1,denom),two))
return 1;
if(!ISZERO(ARG(0,denom)))
return 1;
if(NOTDEFINED(num))
{ errbuf(0, english(863));
/* numerator must be defined and nonzero. */
return 1;
}
if(contains(num,LIMIT))
{ errbuf(0, english(864));
/* First evaluate the numerator */
return 1;
}
err = infer(lessthan(zero,num));
if(!err)
{ *next = infinity;
strcpy(reason, english(1959));
/* lim a/u^2 = \\infty if lim u = 0 and a > 0 */
HIGHLIGHT(*next);
release(polyvalop);
release(arithmetic);
return 0;
}
return 1;
}
/*_____________________________________________________________________*/
int zerosqdenom2(term t, term arg, term *next, char *reason)
{ term num,denom;
int err;
if(FUNCTOR(t) != '/')
return 1;
num = ARG(0,t);
denom = ARG(1,t);
if(FUNCTOR(denom) != '^')
return 1;
if(!equals(ARG(1,denom),two))
return 1;
if(!ISZERO(ARG(0,denom)))
return 1;
if(NOTDEFINED(num))
{ errbuf(0, english(863));
/* numerator must be defined and nonzero. */
return 1;
}
if(contains(num,LIMIT))
{ errbuf(0, english(864));
/* First evaluate the numerator */
return 1;
}
err = infer(lessthan(num,zero));
if(!err)
{ *next = minusinfinity;
strcpy(reason, english(1960));
/* lim a/u^2 = -\\infty if lim u = 0 and a < 0 */
HIGHLIGHT(*next);
release(polyvalop);
release(arithmetic);
return 0;
}
return 1;
}
/*_____________________________________________________________________*/
int zero2ndenom(term t, term arg, term *next, char *reason)
{ term num,denom;
int err;
if(FUNCTOR(t) != '/')
return 1;
num = ARG(0,t);
denom = ARG(1,t);
if(FUNCTOR(denom) != '^')
return 1;
if(!iseven(ARG(1,denom)))
return 1;
if(!ISZERO(ARG(0,denom)))
return 1;
if(NOTDEFINED(num))
{ errbuf(0, english(863));
/* numerator must be defined and nonzero. */
return 1;
}
if(contains(num,LIMIT))
{ errbuf(0, english(864));
/* First evaluate the numerator */
return 1;
}
err = infer(lessthan(zero,num));
if(!err)
{ *next = infinity;
strcpy(reason, english(1961));
/* lim a/u^2^n = \\infty if lim u = 0 and a > 0 */
HIGHLIGHT(*next);
release(polyvalop);
release(arithmetic);
return 0;
}
return 1;
}
/*_____________________________________________________________________*/
int zero2ndenom2(term t, term arg, term *next, char *reason)
{ term num,denom;
int err;
if(FUNCTOR(t) != '/')
return 1;
num = ARG(0,t);
denom = ARG(1,t);
if(FUNCTOR(denom) != '^')
return 1;
if(!iseven(ARG(1,denom)))
return 1;
if(!ISZERO(ARG(0,denom)))
return 1;
if(NOTDEFINED(num))
{ errbuf(0, english(863));
/* numerator must be defined and nonzero. */
return 1;
}
if(contains(num,LIMIT))
{ errbuf(0, english(864));
/* First evaluate the numerator */
return 1;
}
err = infer(lessthan(num,zero));
if(!err)
{ *next = minusinfinity;
strcpy(reason, english(1962));
/* lim a/u^2^n = -\\infty if lim u = 0 and a < 0 */
HIGHLIGHT(*next);
release(polyvalop);
release(arithmetic);
return 0;
}
return 1;
}
Sindbad File Manager Version 1.0, Coded By Sindbad EG ~ The Terrorists