Sindbad~EG File Manager
/*
M. Beeson. One-step limit calculation
10.2.91 Original date
3.30.99 modified
1.4.00 corrected loglim at lines 3249 and 3269
5.29.00 corrected limval_aux near WILD
6.22.04 extended limval to catch lim(x->0+, f(x) e^(1/x)) etc.
added special_exponential_limit and modified select_ccf_arg
8.26.04 Corrected limval_aux arround line 1184 to correctly handle
product of bounded_oscillations and an infinite limit.
1.18.06 added code that calls is_defined and get_definition when taking limits of user-defined functions.
1.2.11 added code at line 2482 to select_pnz_arg
added code to call clear_already before limval_aux is called.
and code to set polyval_negexpflag to 0 before limval_aux is called--its value was saved and reset, but never set.
6.6.13 added code to make limval(log(boundedoscillations)) be boundedoscillations.
6.10.13 Added a case at the end of simple_exponential_limit
12.9.14 modified select_divnumdenom_arg.
9.3.17 corrected loglim
8.8.24 changed math.h to sincos.h
2.18.25 and back again
*/
#include <string.h>
#include <assert.h>
#include <math.h>
#include "globals.h"
#include "ops.h"
#include "calc.h"
#include "prover.h"
#include "polynoms.h"
#include "order.h"
#include "deriv.h"
#include "mplimits.h"
#include "deval.h"
#include "trig.h"
#include "evaltrig.h"
#include "trigpoly.h"
#include "cancel.h"
#include "pvalaux.h" /* twoparts */
#include "limval.h"
#include "limval2.h"
#include "polyquo.h" /* make_polyquo */
#include "maxsub.h" /* maximal_sub */
#include "mpmem.h" /* save_and_reset */
#include "fremark.h" /* contains_zero_denom */
#include "binders.h"
#include "userfunc.h"
static approach approach_aux(approach a, approach b);
static int limlinear2(term t,term *next);
static int divnumdenom3(int topcall, term t, term arg, term *next, approach *l, approach *r);
static int pnz2(term, term *);
static int trig_approaches(unsigned short f, term c, approach ll, approach *ans);
static int finish_limquo(term u, term v, term *ans);
static int finish_limquo2(term u, approach lu, approach ru,
term v, approach lv, approach rv,
term *ans, approach *l, approach *r);
static int unary_lim(unsigned short f, unsigned short dir, term x, term *ans, approach *l, approach *r);
static int simple_exponential_limit(term t, term *ans, approach *l, approach *r);
static int oscillatory(term t, term w);
static int finitelimit(term t, term u);
static int logarithmic(term mid, term h);
static int loglim(int topcall, term t, approach *l, approach *r, term *ans);
static int badlimit(term t);
static int special_exponential_limit(int topcall,term t, term *ans, approach *l, approach *r);
/*_________________________________________________________________*/
static approach approach_product(approach a, approach b, int dir)
/* compute the approach of a product in terms of the
given approaches of its factors. Dir is LEFTDIR or RIGHTDIR,
a and b are either max or min.
*/
{ if(a == max && b == max)
return dir == LEFTDIR ? max : min;
if(a == min && b == min)
return dir == LEFTDIR ? max : min;
if(a == max && b == min) /* negative derivative */
return dir == LEFTDIR ? min : max;
if(a == min && b == max)
return dir == LEFTDIR ? min : max;
return unknown;
}
/*_________________________________________________________________*/
int limval_aux(int topcall,term t, term *ans, approach *l, approach *r)
/* calculate the value and style of left and/or right approach of
the limit term t. Zero return is success at calculating the limit
and the approach; except if the limit is 'undefined', the approaches
need not be computed. Topcall is a flag: if it is nonzero, then
*l and *r are not required, so extra computation only to get them
is suppressed. Return value 1 is failure; return value 2 means
domain error, i.e. the limit point is not in the closure of the
domain of the limitand. */
/* If the limitand is constant, we use approach value min */
{ term h,a,u,v,mid,c,d,dd,num,denom,next,temp,aa,bb,alim,blim,deriv,aderiv;
unsigned short f;
int k;
approach ll,rr,l2,r2;
int saveit, err,err2,cflag,dflag, savecomdenomflag;
unsigned short dir = 0; /* initialize to avoid a warning message */
void *savenode;
double z;
unsigned short n;
int i;
if(FUNCTOR(t) != LIMIT)
return 1;
if(contains(t,ILLEGAL))
return 1; // this is defensive programming, trying to stop crashes
// resulting from too many variables being created.
n = ARITY(t);
assert(FUNCTOR(ARG(0,t))==ARROW);
h = ARG(0,ARG(0,t)); /* the limit variable */
if(!ISATOM(h))
assert(0);
a = ARG(1,ARG(0,t));
if(n==2)
u = ARG(1,t); /* so t = lim(h->a,u) */
else
{ u = ARG(2,t);
dir = equals(ARG(1,t),left) ? LEFTDIR : RIGHTDIR;
}
if(!depends(u,h))
{ *ans = u;
*l = *r = min;
return 0;
}
if(entire(u)&& !ISINFINITE(a))
{ /* u is continuous */
/* You can't use continuity at infinity, e.g. cos(infinity)??
Even if you make that into bounded_oscillations, there are
other more complicated behaviors. */
int savecomdenomflag;
subst(a,h,u,&temp);
savecomdenomflag = get_polyvalcomdenomflag();
set_polyvalcomdenomflag(0);
/* since u is entire nothing is to be gained by, and in
complicated cases much may be paid for, common denominators. */
polyval(temp,ans);
set_polyvalcomdenomflag(savecomdenomflag);
if(topcall || !contains(u,FUNCTOR(h)))
return 0;
/* Now *l and *r are required */
if(ZERO(a) && FUNCTOR(u) == ABSFUNCTOR && equals(ARG(0,u),h))
/* handle the case of lim(h->0, abs(h)) quickly */
{ *l = *r = min;
return 0;
}
deriv = derivative(u,h);
if(ZERO(deriv))
{ *l = *r = min;
return 0;
}
if(obviously_nonnegative(deriv))
{ *l = max;
*r = min;
return 0;
}
if(obviously_nonnegative(strongnegate(deriv)))
{ *l = min;
*r = max;
return 0;
}
subst(a,h,deriv,&temp);
if(contains_zero_denom(temp))
aderiv = undefined;
else
polyval(temp,&aderiv);
if(ZERO(aderiv) || equals(aderiv,undefined))
{ err = infer(le(*ans,u));
if(!err)
{ *l = *r = min;
return 0;
}
err = infer(le(u,*ans));
if(!err)
{ *l = *r = max;
return 0;
}
return 1;
}
if(!infer(le(zero,deriv)))
{ *l = max;
*r = min;
return 0;
}
if(!infer(le(deriv,zero)))
{ *l = min;
*r = max;
return 0;
}
return 1;
}
savenode = heapmax();
int nvars = get_nvariables();
if(equals(u,h))
{ *ans = a;
if(!ATOMIC(a) && !ISINFINITE(a))
/* following code takes care of the possibility that we've
arrived here e.g. with a = 1/0 */
{ if(seminumerical(a))
{ double z;
deval(a,&z);
if(z == BADVAL)
{ reset_heap(savenode);
return 2;
}
}
else if(infer(domain(a)))
{ reset_heap(savenode);
set_nvariables(nvars);
return 2;
}
}
*l = max;
*r = min;
reset_heap(savenode);
return 0;
}
if(ISATOM(u)) /* u was introduced by a let_defn depending on h */
return 1; /* too hard */
if(contains_in_exponent(t,FUNCTOR(h)))
/* get limit of (1/2)^h before it becomes 1/2^h in polyval */
{ err = simple_exponential_limit(t,ans,l,r);
if(!err)
{ save_and_reset(*ans,savenode,ans);
return 0;
}
}
if(!ALREADY(u))
{ saveit = get_polyvaldifflag();
savecomdenomflag = get_polyvalcomdenomflag();
set_polyvaldifflag(1); /* make polyval evaluate derivatives */
if(FUNCTOR(u) == '+')
{ /* should we use common denoms or not?? This code
tries it first without. This works lim(x->0, (sin tan x - tan sin x)/x^2);
and the graph of the deriv of 1/sin(x) + 1/cos(x) takes ten
seconds either way.
*/
set_polyvalcomdenomflag(0);
polyval(u,&mid);
save_and_reset(mid,savenode,&mid);
/* whether or not polyval changed u, we still
should try limval_aux recursively; at least
polyval has marked mid ALREADY so we won't
call polyval again next time. */
v = n==2 ? limit(ARG(0,t),mid) : limit3(ARG(0,t),ARG(1,t),mid);
err = limval_aux(topcall,v,ans,l,r);
if(!err)
{ set_polyvaldifflag(saveit);
set_polyvalcomdenomflag(savecomdenomflag);
return 0;
}
reset_heap(savenode); /* now mid is garbage, but no matter. */
set_polyvalcomdenomflag(savecomdenomflag);
}
err = polyval(u,&mid);
set_polyvaldifflag(saveit);
save_and_reset(mid,savenode,&mid);
if(!err)
{ u = n==2 ? limit(ARG(0,t),mid) : limit3(ARG(0,t),ARG(1,t),mid);
return limval_aux(topcall,u,ans,l,r);
}
u = mid; /* which is a copy, except that the parts of mid are marked
with ALREADY. It's not enough just to SET_ALREADY(u)
and forget about mid */
}
f = FUNCTOR(u);
if(f=='^' && depends(ARG(1,u),h))
{ aa = ARG(0,u);
bb = ARG(1,u);
if(equals(aa,eulere)) /* lim e^b = e^ lim b */
{ mid = ARITY(t)==2 ? limit(ARG(0,t),ARG(1,u)) : limit3(ARG(0,t),ARG(1,t),ARG(1,u));
err = limval_aux(topcall,mid,&c,l,r);
if(err)
{ reset_heap(savenode);
set_nvariables(nvars);
return err;
}
if(equals(c,minusinfinity))
*ans = zero;
else if(equals(c,unbounded_oscillations))
*ans = undefined;
/* unbounded_oscillations means unbounded on both sides,
so nonstandard can infer that it does not have one sign
in the neighborhood of the limit */
else if(NOTDEFINED(c))
/* bounded_oscillations do not have to change sign */
*ans = c;
else if(FUNCTOR(c)==LN)
*ans = ARG(0,c);
else if(ZERO(c))
*ans = one;
else if(ONE(c))
*ans = eulere;
else
polyval(make_power(eulere,c),ans);
save_and_reset(*ans,savenode,ans);
return 0;
}
/* lim a^b = lim e^(b ln a); but this should be used only if a and b
both approach 0. At all other places '^' is continuous. So first
compute the limits of a and b. */
if(!depends(aa,h))
c = aa;
else
{ alim = n==2 ? limit(ARG(0,t),aa) : limit3(ARG(0,t),ARG(1,t),aa);
err = limval_aux(topcall,alim,&c,&ll,&rr);
if(err)
{ reset_heap(savenode);
set_nvariables(nvars);
return err;
}
}
if(!depends(bb,h))
d = bb;
else
{ blim = n==2 ? limit(ARG(0,t),bb) : limit3(ARG(0,t),ARG(1,t),bb);
err = limval_aux(topcall,blim,&d,&l2,&r2);
if(err)
{ reset_heap(savenode);
set_nvariables(nvars);
return err;
}
}
if(equals(c,infinity) && equals(d,infinity))
{ *ans = infinity;
reset_heap(savenode);
return 0;
}
if(equals(c,infinity) &&
(equals(d,bounded_oscillations) ||
equals(d,unbounded_oscillations) ||
equals(d,undefined)
)
)
{ *ans = undefined;
reset_heap(savenode);
return 0;
}
if(equals(c,minusinfinity))
{ /* Theoretically the exponent might have a been equal to an
odd-denominator rational even though it depends on h,
e.g. 1/3 + h - h; but it's been through polyval, so it
couldn't be that. Let's take the risk of assuming
it is not constant. It could be, for instance,
1/3 + h f(pi_term,e) where f(pi_term,e) == 0 but we don't know it.
*/
*ans = undefined;
reset_heap(savenode);
set_nvariables(nvars);
return 2;
}
if(!ZERO(c))
{ err = check1(le(zero,c));
if(err)
{ reset_heap(savenode);
set_nvariables(nvars);
return 2; /* domain error */
}
err = check1(lessthan(zero,c));
if(err)
c = zero;
}
cflag = NOTDEFINED(c);
dflag = NOTDEFINED(d);
if(ZERO(c) && !ZERO(d) && !dflag)
{ *ans = zero;
reset_heap(savenode);
return 0;
}
if(!cflag && !dflag &&
(!ZERO(c) || !ZERO(d))
)
{ if(ZERO(c))
{ reset_heap(savenode);
*ans = zero;
return 0;
}
else if(ZERO(d))
{ reset_heap(savenode);
*ans = one;
return 0;
}
else if(ONE(d))
{ save_and_reset(c,savenode,ans);
return 0;
}
else
{ polyval(make_power(c,d),&temp);
save_and_reset(temp,savenode,ans);
return 0;
}
}
/* Now proceed with lim a^b = lim e^(b ln a) */
c = make_power(eulere,product(ARG(1,u),ln1(ARG(0,u))));
SET_ALREADY(c); /* otherwise polyval takes it apart again, causing
an infinite regress. */
mid = ARITY(t)==2 ? limit(ARG(0,t),c) : limit3(ARG(0,t),ARG(1,t),c);
err = limval_aux(topcall,mid,&temp,l,r);
if(err)
{ reset_heap(savenode);
set_nvariables(nvars);
return err;
}
else
{ save_and_reset(temp,savenode,ans);
return 0;
}
}
if(f == '^') /* and exponent is constant */
{ term power = ARG(1,u);
dd = n==2 ? limit(ARG(0,t),ARG(0,u)) : limit3(ARG(0,t),ARG(1,t),ARG(0,u));
err = limval_aux(topcall,dd,&mid,&ll,&rr);
if(err)
{ reset_heap(savenode);
set_nvariables(nvars);
return err;
}
if(ZERO(mid))
{ approach l1,r1;
err = finish_it(n,dir,power,ans,&l1,&r1);
if(err)
{ reset_heap(savenode);
set_nvariables(nvars);
return 1;
}
if(ISINFINITE(*ans) &&
(
(n == 2 && l1==bounded_oscillation) ||
(n == 2 && r1==bounded_oscillation) ||
(n == 3 && equals(ARG(1,t),left) && l1==bounded_oscillation) ||
(n == 3 && equals(ARG(1,t),right) && r1==bounded_oscillation)
)
)
{ *l = *r = unbounded_oscillation;
*ans = unbounded_oscillations;
reset_heap(savenode);
return 0;
}
*l = ll == max ? l1 : ll == min ? r1 : ll;
*r = rr == min ? r1 : rr == min ? l1 : rr;
save_and_reset(*ans,savenode,ans);
return 0;
}
if(!NOTDEFINED(mid))
{ polyval(make_power(mid,power),ans);
if(topcall && (INTEGERP(power) || obviously_positive(mid)))
{ save_and_reset(*ans,savenode,ans);
return 0;
}
err = infer(domain(*ans));
if(topcall && !err)
{ save_and_reset(*ans,savenode,ans);
return 0;
}
if(err == 2)
{ *ans = undefined;
reset_heap(savenode);
return 0; /* domain error, as in lim (x->-1, x^(1/2)) */
}
/* Now must get *l and *r from ll and rr */
/* Is x^power increasing or decreasing at mid?
This is determined by the sign of power * mid^(power-1) */
err = check1(lessthan(zero,mid));
if(!err)
{ err = check1(lessthan(zero,power));
if(!err)
{ *l = ll;
*r = rr;
}
else
{ *l = REVERSE(ll);
*r = REVERSE(rr);
}
save_and_reset(*ans,savenode,ans);
return 0;
}
else /* mid is negative */
{ err = check1(lessthan(zero,power));
err2 = infer(lessthan(zero,make_power(minusone,power)));
if(err2 ^ err) /* exclusive or */
{ *l = ll;
*r = rr;
}
else
{ *l = REVERSE(ll);
*r = REVERSE(rr);
}
save_and_reset(*ans,savenode,ans);
return 0;
}
}
if(WILD(mid))
{ *l = ll;
*r = rr;
*ans = mid;
reset_heap(savenode);
return 0;
}
if(equals(mid,infinity))
{ err = check1(lessthan(zero,power));
if(!err)
{ *ans = infinity;
*l = *r = max;
}
else /* power == zero is impossible, it would have been polyval'd away */
{ *ans = zero;
*l = *r = min;
}
reset_heap(savenode);
return 0;
}
if(equals(mid,minusinfinity))
/* as x-> minus infinity, x^n -> \pm infinity (positive n)
or zero (negative n) */
{ err = check1(lessthan(zero,power));
err2 = infer(lessthan(zero,make_power(minusone,power)));
/* for integer powers, err2 is zero if power is even */
if(!err && err2) /* positive odd power */
{ *ans = minusinfinity;
*l = ll;
*r = rr;
reset_heap(savenode);
return 0;
}
else if(!err) /* positive even power */
{ *ans = infinity;
*l = INVERT_APPROACH(ll);
*r = INVERT_APPROACH(rr);
reset_heap(savenode);
return 0;
}
else if(err2) /* negative odd power */
{ *ans = zero;
*l = INVERT_APPROACH(ll);
*r = INVERT_APPROACH(rr);
reset_heap(savenode);
return 0;
}
else /* negative even power */
{ *ans = zero;
*l = ll;
*r = rr;
reset_heap(savenode);
return 0;
}
}
}
if(f == '-')
{ mid = n==2 ? limit(ARG(0,t),ARG(0,u)) : limit3(ARG(0,t),ARG(1,t),ARG(0,u));
err = limval_aux(topcall,mid,&c,&ll,&rr);
if(err)
{ reset_heap(savenode);
set_nvariables(nvars);
return err;
}
if(WILD(c))
*ans = c;
else
tneg(c,ans);
*l = ll==min ? max : ll == max ? min : ll;
*r = rr==min ? max : rr == max ? min : rr;
save_and_reset(*ans,savenode,ans);
return 0;
}
if(f == SQRT)
{ mid = make_power(ARG(0,u),make_fraction(one,two));
temp = n==2 ? limit(ARG(0,t),mid) : limit3(ARG(0,t),ARG(1,t),mid);
save_and_reset(temp,savenode,&d);
return limval_aux(topcall,d,ans,l,r);
}
if(f == ROOT)
{ mid = make_power(ARG(1,u),make_fraction(one,ARG(0,u)));
temp = n==2 ? limit(ARG(0,t),mid) : limit3(ARG(0,t),ARG(1,t),mid);
save_and_reset(temp,savenode,&d);
return limval_aux(topcall,d,ans,l,r);
}
if(TRIGFUNCTOR(f) && equals(ARG(0,u),h) && !seminumerical(a))
/* example: lim(h->2(n+1)x/2, tan h) */
{ term b,c;
b = make_term(f,1);
ARGREP(b,0,a);
err = periodic(b,&c); /* tan((2n+1)x/2) = tan(x/2) */
if(!err) /* reduce to lim(h->x/2, tan h) */
{ temp = n==2 ? limit(arrow(h,ARG(0,c)),u) : limit3(arrow(h,ARG(0,c)),ARG(1,t),u);
save_and_reset(temp,savenode,&d);
return limval_aux(topcall,d,ans,l,r);
}
if(f == COS && topcall && FRACTION(a) && equals(ARG(1,a),two) &&
FUNCTOR(ARG(0,a)) == '*' && ARITY(ARG(0,a))== 2 && equals(ARG(1,ARG(0,a)),pi_term) &&
FUNCTOR(ARG(0,ARG(0,a))) == '+' &&
ONE(ARG(1,ARG(0,ARG(0,a)))) &&
FUNCTOR(ARG(0,ARG(0,ARG(0,a)))) == '*' && ARITY(ARG(0,ARG(0,ARG(0,a)))) == 2 &&
equals(ARG(0,ARG(0,ARG(0,ARG(0,a)))),two) &&
isinteger(ARG(1,ARG(0,ARG(0,ARG(0,a)))))
)
/* lim(x->(2n+1)pi/2, cos x) = 0 */
{ *ans = zero;
reset_heap(savenode);
return 0;
}
}
if(f== SIN || f==COS || f==ABSFUNCTOR)
{ mid = n==2 ? limit3(ARG(0,t),left,ARG(0,u)) : limit3(ARG(0,t),ARG(1,t),ARG(0,u));
/* compute both one-sided limits when n==2, otherwise you
won't get sin(1/x + 1/x^2) to have bounded_oscillation */
err = limval_aux(topcall,mid,&c,&ll,&rr);
if(err)
{ reset_heap(savenode);
set_nvariables(nvars);
return err;
}
if(n==2) /* compute the other one-sided limit */
{ mid = limit3(ARG(0,t),right,ARG(0,u));
err = limval_aux(topcall,mid,&d,&l2,&r2);
if(err)
{ reset_heap(savenode);
set_nvariables(nvars);
return err;
}
rr = r2;
}
if(!NOTDEFINED(c))
{ if(n==2 && !equals(c,d)) /* right and left limits not equal */
{ /* in principle it still might be ok, e.g. if the left
and right limits differ by 2 pi */
double z;
if(f==ABSFUNCTOR)
{ *ans = undefined;
reset_heap(savenode);
return 0;
}
temp = f==SIN ? sum(sin1(c),tnegate(sin1(d))) : sum(cos1(c),tnegate(cos1(d)));
polyval(temp,&dd);
if(!ISZERO(dd))
{ if(!seminumerical(dd))
{ *ans = undefined; /* in principle this might be wrong,
if dd really is zero but we just can't prove
it with polyval. I can't think of an example. */
reset_heap(savenode);
return 0;
}
err = deval(dd,&z);
if(err || fabs(z) > 1.0e-15)
{ *ans = undefined;
reset_heap(savenode);
return 0;
}
}
}
if(f==SIN)
mid = sin1(c);
else if(f==COS)
mid = cos1(c);
else
{ assert(f==ABSFUNCTOR);
if(numerical(c))
{ double z;
long kk;
err=deval(c,&z);
if(!err && nearint(z,&kk))
mid = kk >= 0 ? c : tnegate(c);
else if(!err)
mid = z > 0.0 ? c : tnegate(c);
}
else
mid = abs1(c);
}
if(NUMBER(mid) || OBJECT(mid))
*ans = mid;
else
{ saveit = get_polyvalfunctionflag();
set_polyvalfunctionflag(1);
polyval(mid,ans);
set_polyvalfunctionflag(saveit);
}
if(topcall)
{ save_and_reset(*ans,savenode,ans);
return 0; /* *l and *r are not required */
}
/* Now determine *l and *r from ll and rr */
err = trig_approaches(f,c,ll,l);
if(err)
{ reset_heap(savenode);
set_nvariables(nvars);
return 1;
}
err = trig_approaches(f,c,rr,r);
if(err)
{ reset_heap(savenode);
set_nvariables(nvars);
return 1;
}
save_and_reset(*ans,savenode,ans);
return 0;
}
if(f == ABSFUNCTOR)
{ if(n == 3)
{ if(ISINFINITE(c))
{ *ans = infinity;
*l = *r = max;
return 0;
}
if(equals(c, bounded_oscillations))
{ *ans = bounded_oscillations;
*l = *r = bounded_oscillation;
return 0;
}
*ans = undefined;
*l = ll;
*r = rr;
return 0;
}
if(n == 2)
{ if(ISINFINITE(c) && ISINFINITE(d))
{ *ans = infinity;
*l = *r = max;
return 0;
}
if(equals(c,d))
{ *ans = c;
*l = ll;
*r = rr;
return 0;
}
}
}
if(
equals(c,infinity) || equals(c,minusinfinity) ||
equals(c,unbounded_oscillations) || equals(c,bounded_oscillations)
|| (n==2 && (equals(d,infinity) || equals(d,minusinfinity)))
)
/* this includes lim(x->infinity, sin(x sin x))
and lim(x->infinity,sin(sin(1/x))) */
{ *ans = bounded_oscillations;
*l = ll==dom_error ? ll : bounded_oscillation;
*r = rr==dom_error ? rr : bounded_oscillation;
reset_heap(savenode);
return 0;
}
if(equals(c,undefined))
{ *ans = undefined;
*l = ll;
*r = rr;
reset_heap(savenode);
return 0;
}
if(topcall && !NOTDEFINED(c))
{ save_and_reset(*ans,savenode,ans);
return 0;
}
if(topcall)
{ *ans = c;
reset_heap(savenode);
return 0;
}
if(seminumerical(c))
{ double z;
long k;
err = deval(f==SIN ? cos1(c) : tnegate(sin1(c)),&z);
if(err)
return 1;
if(nearint(z,&k) && k==0) /* at a max or min */
{ deval(*ans,&z);
if(z < 0.0) /* a minimum */
{ *r = rr;
*l = INVERT_APPROACH(ll);
}
else /* a max */
{ *l = ll;
*r = INVERT_APPROACH(rr);
}
save_and_reset(*ans,savenode,ans);
return 0;
}
if(z > 0.0) /* increasing */
{ *r = rr;
*l = ll;
save_and_reset(*ans,savenode,ans);
return 0;
}
else
{ *r = INVERT_APPROACH(rr);
*l = INVERT_APPROACH(ll);
save_and_reset(*ans,savenode,ans);
return 0;
}
}
/* if you get here, as with lim(x->a, sin(sin(x))),
you can still go on. You'll get it below when you differentiate
directly. */
}
if(f == LN || f == LOG || f== LOGB)
{ dd = f == LN ? ARG(0,u) : f== LOG ? ARG(0,u) : ARG(1,u);
d = n==2 ? limit(ARG(0,t),dd) : limit3(ARG(0,t),ARG(1,t),dd);
err = limval_aux(0,d,&c,&ll,&rr);
if(err)
{ save_and_reset(d,savenode,&d);
set_nvariables(nvars);
err = limval_aux(1,d,&c,&ll,&rr);
if( err || ZERO(c))
{ reset_heap(savenode);
set_nvariables(nvars);
return 1;
}
}
if(ZERO(c))
/* Now it matters whether dd has one sign in a neighborhood of a or not */
{ if(n==2 && ll==min && rr ==min)
{ *ans = minusinfinity;
*l = *r = min;
reset_heap(savenode);
return 0;
}
if(n==3 && equals(ARG(1,t),left) && ll==min)
{ *ans = minusinfinity;
*l = min;
*r = rr==min ? min : dom_error;
reset_heap(savenode);
return 0;
}
if(n==3 && equals(ARG(1,t),right) && rr==min)
{ *ans = minusinfinity;
*r = min;
*l = ll==min ? min : dom_error;
reset_heap(savenode);
return 0;
}
*ans = undefined;
*l = *r = dom_error;
reset_heap(savenode);
return 0;
/* lim(t->0-, ln t) comes here, but also more
complicated things, for example,
lim(t->0+, ln(t sin(1/t))). We still return
0 with approach dom_error even in this case,
because at least it's NOT a singularity, so
the grapher can go ahead and draw it
*/
}
*l = ll;
*r = rr;
if(equals(c,infinity) || equals(c,undefined))
{ *ans = c;
reset_heap(savenode);
return 0;
}
if(ONE(c))
{ *ans = zero;
reset_heap(savenode);
return 0;
}
if( (f==LOG && equals(c,ten)) || (f == LN && equals(c,eulere)))
{ *ans = one;
reset_heap(savenode);
return 0;
}
if (FUNCTOR(c)=='^' && equals(ARG(0,c),f==LN ? eulere : ten))
{ save_and_reset(ARG(1,c),savenode,ans);
return 0;
}
if(equals(c,minusinfinity))
{ *ans = undefined;
*l = *r = dom_error;
reset_heap(savenode);
return 0;
}
if(equals(c,bounded_oscillations))
{ *ans = bounded_oscillations;
*l = *r = bounded_oscillation;
reset_heap(savenode);
return 0;
}
err = check1(lessthan(zero,c));
if(err)
{ reset_heap(savenode);
set_nvariables(nvars);
return 2; /* domain error */
}
temp = f==LN ? ln1(c) : log1(c);
save_and_reset(temp,savenode,ans);
return 0;
}
if(f == '*' || f == '/') /* pull out constants ? */
{ err = limlinear2(t,&mid);
if(!err)
{ unsigned short m = ARITY(mid);
term coef;
/* mid is a product whose last term is a LIMIT, but there can
be more than two terms in the product, e.g. if t was
lim(h->0, 3xh) then mid will be 3x lim(h->0,h) */
assert(FUNCTOR(mid) == '*' && FUNCTOR(ARG(m-1,mid))==LIMIT);
err = limval_aux(topcall,ARG(m-1,mid),&c,l,r);
if(err)
{ reset_heap(savenode);
set_nvariables(nvars);
return 1;
}
if(m==2)
coef = ARG(0,mid);
else
{ coef = mid;
SETFUNCTOR(coef,'*',(unsigned short)(m-1)); /* ignore the last arg */
}
if(NOTDEFINED(c))
{ err = check1(nonzero(coef));
if(!err)
{ if(WILD(c))
*ans = c;
else if(equals(c,infinity))
{ err = check1(le(zero,coef));
if(!err)
*ans = infinity;
else
*ans = minusinfinity;
}
else if(equals(c,minusinfinity))
{ err = check1(le(zero,coef));
if(!err)
*ans = minusinfinity;
else
*ans = infinity;
}
else
assert(0); /* NOTDEFINED means WILD or ISINFINITE */
reset_heap(savenode);
return 0;
}
else
{ reset_heap(savenode);
set_nvariables(nvars);
return 1;
} /* limlinear2 shouldn't produce a zero coefficient anyway */
}
polyval(product(coef,c),&temp);
save_and_reset(temp,savenode,ans);
return 0;
}
}
if(!ISINFINITE(a) && trigalg2(u,h))
/* rational function of h, rational powers of h, and trig functions of h */
goto leadingterm;
if(ISINFINITE(a) && algebraic_in2(u,h))
goto leadingterm;
/* at infinity, trig functions have no leading term */
if(f == '*' ||
(FRACTION(u) && (FUNCTOR(ARG(0,u)) == '*' || FUNCTOR(ARG(1,u)) == '*'))
) /* there must be a product in num or denom, or pulloutnonzerolimit
can't possibly work. */
err = pnz2(t,&mid);
else
err = 1;
if(!err) /* pulloutnonzerolimit (or the equivalent pnz2) worked */
{ assert(FUNCTOR(mid) == '*' && ARITY(mid)==2 && FUNCTOR(ARG(1,mid))==LIMIT);
err = limval_aux(topcall,ARG(0,mid),&c,&ll,&rr);
if(err)
{ reset_heap(savenode);
set_nvariables(nvars);
return 1;
}
err = limval_aux(topcall,ARG(1,mid),&d,&l2,&r2);
if(err)
{ reset_heap(savenode);
set_nvariables(nvars);
return 1;
}
if(NOTDEFINED(d))
{ *l = l2;
*r = r2;
*ans = d;
reset_heap(savenode);
set_nvariables(nvars);
return 0;
}
save_and_reset(product(c,d),savenode,ans);
if(topcall)
return 0;
if((n==2 || (n==3 && dir == RIGHTDIR)) && rr==damped_oscillation)
{ if (r2==damped_oscillation)
{ reset_heap(savenode);
set_nvariables(nvars);
return 1;
}
else
*r = damped_oscillation;
}
if((n==2 || (n==3 && dir == LEFTDIR)) && ll==damped_oscillation)
{ if (l2==damped_oscillation)
{ reset_heap(savenode);
set_nvariables(nvars);
return 1;
}
else
*l = damped_oscillation;
}
if( ((n==2 || (n==3 && dir == RIGHTDIR)) && rr==damped_oscillation)
||((n==2 || (n==3 && dir == LEFTDIR)) && ll==damped_oscillation)
)
return 0;
/* Now r2,rr,l2,ll are max or min, and d came out to a
finite limit. Must compute *l and *r */
*l = approach_product(l2,ll,LEFTDIR);
*r = approach_product(r2,rr,RIGHTDIR);
return 0;
} /* finished with pulloutnonzerolimit */
SETFUNCTOR(temp,ILLEGAL,0);
if(f == '/') /* and it's not a rational function */
{ err = special_exponential_limit(topcall,t,ans,l,r);
if(!err)
return 0;
err = divnumdenom3(topcall,t,temp,ans,l,r);
if(!err)
{ save_and_reset(*ans,savenode,ans);
return 0;
}
err = limvalquo_aux(topcall,t,ans,l,r);
if(err)
{ reset_heap(savenode);
set_nvariables(nvars);
return err;
}
save_and_reset(*ans,savenode,ans);
return 0;
}
/* Now u is not a quotient */
if((f == '*' || f == '/') && ARITY(u) == 2 &&
(
( FUNCTOR(ARG(1,u)) == LN ||
(FUNCTOR(ARG(1,u)) == '^' && FUNCTOR(ARG(0,ARG(1,u))) == LN)
) ||
( FUNCTOR(ARG(0,u)) == LN ||
(FUNCTOR(ARG(0,u)) == '^' && FUNCTOR(ARG(0,ARG(0,u))) == LN)
)
)
)
{ err = loglim(topcall,t,l,r,ans); // l and r were switched, corrected 6.8.13
if(!err)
{ save_and_reset(*ans,savenode,ans);
return 0;
}
}
if(f=='*' || f== '+')
/* Try lim(u+v)=lim u + lim v, lim uv = (lim u) (lim v) */
{ int infinityflag = -1;
int infinitysign = 1;
int polyzeroflag = 0;
int logzeroflag = 0;
int countzeroes = 0;
int polyinfinityflag = 0;
int loginfinityflag = 0;
int bounded_oscillationsflag = 0;
int unbounded_oscillationsflag = 0;
int directionflag = 0; /* whether approach direction has been initialized */
int directionsignflag = 1; /* set to -1 when negative constant comes first in a product */
int k = 0; /* count the infinite terms */
temp = make_term(f,ARITY(u));
for(i=0;i<ARITY(u);i++)
{ mid = ARG(i,u);
if(!depends(mid,h)) /* skip constant terms */
{ ARGREP(temp,i,mid);
if(!topcall && FUNCTOR(u) == '*')
{ err = check1(lessthan(zero,mid));
if(err && directionflag)
{ *l = REVERSE(*l);
*r = REVERSE(*r);
}
else if(err)
directionsignflag = -1; /* negative constant before any nonconstant in the product */
}
continue;
}
dd = n==2 ? limit(ARG(0,t),mid) : limit3(ARG(0,t),ARG(1,t),mid);
err = limval_aux(topcall,dd,&c,&ll,&rr);
if(err == 2)
{ *ans = undefined;
reset_heap(savenode);
set_nvariables(nvars);
return 2; /* domain error */
}
if(err)
goto leadingterm;
if(!err && equals(c,undefined))
{ *ans = undefined;
*l = *r = dom_error;
reset_heap(savenode);
return 0;
}
if(equals(c,bounded_oscillations))
++bounded_oscillationsflag;
else if(equals(c,unbounded_oscillations))
++unbounded_oscillationsflag;
else if(ZERO(c))
{ ++countzeroes;
if(algpoly3(mid))
++polyzeroflag;
else if(
(FUNCTOR(mid) == LN || FUNCTOR(mid) == LOG) &&
algpoly3(ARG(0,mid))
)
++logzeroflag;
}
else if(!ISINFINITE(c) && check1(nonzero(c))) /* check returns 0 for success */
++countzeroes; /* check1(nonzero(c)) failed, so c was either
proved or assumed to be zero. */
if(!topcall && directionflag==0)
{ *l = directionsignflag == 1 ? ll : REVERSE(ll);
*r = directionsignflag == 1 ? rr: REVERSE(rr);
directionflag = directionsignflag = 1;
}
if(ISINFINITE(c) && infinityflag== -1) /* the first infinite term in this sum or product */
{ infinityflag = i;
if(NEGATIVE(c))
infinitysign = -1;
*l = ll;
*r = rr;
*ans = c;
++k; /* count the infinite terms */
if(algebraic_in2(mid,h))
++polyinfinityflag;
else if(
FUNCTOR(mid) == LN &&
algrat(ARG(0,mid))
)
++loginfinityflag;
else if(logarithmic(mid,h))
++loginfinityflag;
if(f == '*' &&
polyzeroflag && polyinfinityflag &&
!bounded_oscillationsflag &&
!unbounded_oscillationsflag
)
goto leadingterm;
}
else if(ISINFINITE(c) && (f =='*' || equals(c,ARG(infinityflag,temp))))
{ if(NEGATIVE(c) && f == '*')
infinitysign = infinitysign < 0 ? 1 : -1;
if(algebraic_in2(mid,h))
++polyinfinityflag;
if(logarithmic(mid,h))
++loginfinityflag;
++k; /* count the infinite terms */
if(f == '*' &&
polyzeroflag && polyinfinityflag &&
!bounded_oscillationsflag &&
!unbounded_oscillationsflag
)
goto leadingterm;
ARGREP(temp,i,c);
continue; /* two of the same direction infinity is ok in a sum,
and any infinities of both signs are ok in a
product */
}
else if(f== '*' && ZERO(c) &&
polyzeroflag && polyinfinityflag &&
!bounded_oscillationsflag &&
!unbounded_oscillationsflag
)
goto leadingterm;
/* infinity times zero is indeterminate */
else if(!err && equals(c,undefined) && (ll==dom_error || rr == dom_error))
{ /* example, lim(x->0-, x ln x) */
*ans = undefined;
*l = ll;
*r = rr;
reset_heap(savenode);
return 0;
}
else if(!err && ISINFINITE(c) && trigalg2(u,h))
goto leadingterm; /* infinities of different signs in a sum */
else if(!err && ISINFINITE(c) && f == '+' && loginfinityflag == k && algebraic_in2(mid,h))
{ /* all previous infinities were logarithmic, but this one is algebraic,
so it dominates */
*ans = c;
*l = ll;
*r = rr;
infinityflag = i;
}
else if(!err && ISINFINITE(c) && f == '+' && loginfinityflag == 0 && logarithmic(mid,h))
{ ++loginfinityflag;
continue; /* neglect this infinity */
}
else if(!err && ISINFINITE(c) && f == '+' && k==1)
{ /* example: u = e^h - h^2, opposite sign infinities,
only one infinity before this one (if there were two
we wouldn't be sure which was dominant), and the limitand
is not trigalg2 so didn't go to leadingterm. */
term p,q,s,zz;
p = ARG(infinityflag,u); /* the previous infinite term */
/* Which one dominates, p or mid? */
q = make_fraction(p,mid);
s = n==2 ? limit(ARG(0,t),q): limit3(ARG(0,t),ARG(1,t),q);
err = limval(s,&zz);
if(!err && ZERO(zz))
{ /* then mid dominates. Limit of u is limit of mid. */
*ans = c;
*l = ll;
*r = rr;
infinityflag = i;
}
else if(err || !ISINFINITE(zz))
{ reset_heap(savenode);
set_nvariables(nvars);
return 1; /* fail, infinities of different signs, neither one
dominates, leadingterm can't work... */
}
/* else p dominates mid, need not do anything */
}
else if(err || equals(c,undefined))
goto leadingterm;
if(!topcall && infinityflag == -1 && (ll != *l || rr != *r))
goto leadingterm; /* directions different */
ARGREP(temp,i,c);
}
if(infinityflag >= 0 )
{ if(k != polyinfinityflag + loginfinityflag)
{ /* e^x + 1 gets here */
if(f == '+' ||
( f == '*' && !countzeroes && !bounded_oscillationsflag && !unbounded_oscillationsflag)
)
{ reset_heap(savenode);
*ans = infinitysign > 0 ? infinity : minusinfinity;
*l = *r = max;
return 0;
}
if(f == '*' && (bounded_oscillationsflag || unbounded_oscillationsflag))
{ *ans = unbounded_oscillations;
*l = *r = unbounded_oscillation;
return 0;
}
goto leadingterm;
}
if(f == '*' && countzeroes != logzeroflag + polyzeroflag)
goto leadingterm;
if(f == '*' && polyinfinityflag && polyzeroflag)
goto leadingterm; /* assert(0) */
if(f == '*')
{ /* logarithmic zeroes or infinities can be ignored if
there are algebraic zeroes or infinities */
if(polyinfinityflag && !polyzeroflag)
{ *ans = infinitysign == -1 ?
tnegate(ARG(infinityflag,temp)):
ARG(infinityflag,temp);
save_and_reset(*ans,savenode,ans);
return 0;
}
if(polyzeroflag && !polyinfinityflag)
{ *ans = zero;
reset_heap(savenode);
return 0;
}
}
else if(f == '+')
{ if(equals(ARG(infinityflag,temp),infinity))
{ *ans = infinity;
*l = *r = max;
}
else
{ *ans = minusinfinity;
*r = *l = min;
}
reset_heap(savenode);
return 0;
}
goto leadingterm; /* it can't do much good but why not try. */
}
if(infinityflag >= 0)
{ if((bounded_oscillationsflag || unbounded_oscillationsflag) && f == '*')
{ *ans = unbounded_oscillations;
*r = *l = unbounded_oscillation;
reset_heap(savenode);
return 0;
}
*ans = infinitysign == -1 ?
tnegate(ARG(infinityflag,temp)):
ARG(infinityflag,temp);
save_and_reset(*ans,savenode,ans);
return 0;
}
if(unbounded_oscillationsflag)
{ *ans = unbounded_oscillations;
*r = *l = unbounded_oscillation;
reset_heap(savenode);
return 0;
}
if(bounded_oscillationsflag)
{ *ans = bounded_oscillations;
reset_heap(savenode);
return 0;
}
if( i==ARITY(u) ) /* evaluated every factor's limit to a value */
{ int saveit = get_polyvalfractexpflag();
set_polyvalfractexpflag(1);
/* otherwise it can't see that (1+x)^(1/2) - sqrt(1+x) is zero */
clear_already(&temp);
polyval(temp,ans);
set_polyvalfractexpflag(saveit);
save_and_reset(*ans,savenode,ans);
return 0;
}
RELEASE(temp);
}
if(UNARY(f))
{ /* f isn't a trig function or ln or log, because these have
already been dealt with */
mid = ARITY(t) == 2 ? limit(ARG(0,t),ARG(0,u)): limit3(ARG(0,t),ARG(1,t),ARG(0,u));
err = limval_aux(topcall,mid,&temp,&l2,&r2);
if(err)
{ reset_heap(savenode);
set_nvariables(nvars);
return err;
}
if(equals(temp,undefined))
{ *ans = undefined;
reset_heap(savenode);
return 0;
}
if(equals(temp, bounded_oscillations))
{ *ans = bounded_oscillations;
*l = *r = bounded_oscillation;
reset_heap(savenode);
return 0;
}
if(equals(temp, unbounded_oscillations))
{ if(f == TANH || f == ATAN || f == ACOT)
{ *ans = bounded_oscillations;
*l = *r = bounded_oscillation;
reset_heap(savenode);
return 0;
}
*ans = undefined;
reset_heap(savenode);
return 0;
}
/* Now temp is infinity, minusinfinity, or a finite value */
if(equals(temp,infinity))
{ switch(f)
{ case ATAN:
case ASEC:
*ans = piover2;
*l = *r = max;
reset_heap(savenode);
return 0;
case ACOT:
*ans = zero;
*l = *r = min;
reset_heap(savenode);
return 0;
case TANH:
case COTH:
*ans = one;
*l = *r = max;
reset_heap(savenode);
return 0;
case SINH:
case COSH:
case ASINH:
case ACOSH:
*ans = infinity;
*l = *r = max;
reset_heap(savenode);
return 0;
case SECH:
case CSCH:
case ACSC:
*ans = zero;
*l = *r = min;
reset_heap(savenode);
return 0;
case ATANH:
case ASECH:
case ACOS:
case ASIN:
*ans = undefined;
*l = *r = dom_error;
reset_heap(savenode);
set_nvariables(nvars);
return 2;
case ACSCH:
*ans = zero;
*l = *r = min;
reset_heap(savenode);
return 0;
case BESSELJ:
case BESSELI:
case BESSELY:
case BESSELK:
*ans = unbounded_oscillations;
*l = *r = unbounded_oscillation;
reset_heap(savenode);
return 0;
}
return 1;
}
if(equals(temp,minusinfinity))
{ switch(f)
{ case ATAN:
reset_heap(savenode);
*ans = piover2;
*l = *r = min;
return 0;
case ACOT:
*ans = pi_term;
*l = *r = max;
reset_heap(savenode);
return 0;
case ASEC:
*ans = piover2;
*l = *r = max;
reset_heap(savenode);
return 0;
case TANH:
case COTH:
*ans = minusone;
*l = *r = min;
reset_heap(savenode);
return 0;
case SINH:
*ans = minusinfinity;
*l = *r = min;
reset_heap(savenode);
return 0;
case COSH:
*ans = infinity;
reset_heap(savenode);
*l = *r = max;
return 0;
case ASINH:
*ans = minusinfinity;
*l = *r = min;
reset_heap(savenode);
return 0;
case ACOSH:
*ans = undefined;
*l = dom_error;
reset_heap(savenode);
return 2;
case SECH:
*ans = zero;
*l = *r = min;
reset_heap(savenode);
return 0;
case CSCH:
*ans = zero;
*l = *r = max;
reset_heap(savenode);
return 0;
case ACSC:
*ans = zero;
*l = *r = max;
reset_heap(savenode);
return 0;
case ATANH:
case ASECH:
case ACOS:
case ASIN:
*ans = undefined;
*l = *r = dom_error;
reset_heap(savenode);
set_nvariables(nvars);
return 2;
case ACSCH:
*ans = zero;
*l = *r = max;
reset_heap(savenode);
return 0;
case BESSELJ:
case BESSELI:
case BESSELY:
case BESSELK:
*ans = undefined;
*l = *r = dom_error;
reset_heap(savenode);
return 0;
}
reset_heap(savenode);
set_nvariables(nvars);
return 1;
}
/* Now temp is finite. Just return *ans = f(temp), if this is defined. */
if(f == BESSELJ || f == BESSELK || f == BESSELI || f == BESSELY)
{ dd = make_term(f,2);
ARGREP(dd,0,ARG(0,u));
ARGREP(dd,1,temp);
}
else
{ dd = make_term(f,1);
ARGREP(dd,0,temp);
}
if(topcall && seminumerical(temp) && !deval(dd,&z) && z != BADVAL)
{ polyval(dd,ans);
save_and_reset(*ans,savenode,ans);
return 0;
}
RELEASE(dd);
if(f == BESSELJ || f == BESSELK || f == BESSELI || f == BESSELY)
{ reset_heap(savenode);
set_nvariables(nvars);
return 1; /* you could get the approaches seminumerically I suppose. */
}
if(ARITY(t) == 3)
dir = equals(ARG(1,t),left) ? LEFTDIR : RIGHTDIR;
else
dir = 0;
err = unary_lim(f, dir, temp,ans,&ll,&rr);
if(err)
{ reset_heap(savenode);
return err;
}
/* Now adjust ll and rr using l2 and r2 to get *l and *r */
*l = l2 == max ? ll : l2 == min ? rr : l2;
*r = r2 == min ? rr : r2 == max ? ll : r2;
polyval(*ans,ans);
save_and_reset(*ans,savenode,ans);
return 0;
}
if((k=is_defined(f)) != -1)
{ /* limit of user-defined function */
term lhs, rhs;
get_definition(k,&lhs,&rhs);
if(n==2)
return limval_aux(topcall,limit(ARG(0,t),rhs),ans,l,r);
else
return limval_aux(topcall,limit3(ARG(0,t),ARG(1,t),rhs),ans,l,r);
}
if(FUNCTOR(u) == CASES)
{ /* is the limit being taken at a jump or a singularity? */
int m = ARITY(u); /* the number of cases */
term condition,leftu,rightu, ansleft, ansright;
int i, err2;
unsigned short F;
approach l1,l2,r1,r2;
l1 = l2 = r1 = r2 = unknown;
SETFUNCTOR(leftu,ILLEGAL,0);
SETFUNCTOR(rightu,ILLEGAL,0);
for(i=0;i<m;i++)
{ /* are the cases going to make the limit point a (possible) jump? */
condition = ARG(0,ARG(i,u)); /* the first arg of the 'if' */
F = FUNCTOR(condition);
if((F == '<' || F == LE) && equals(ARG(1,condition),a) && equals(ARG(0,condition),h))
leftu = ARG(1,ARG(i,u));
else if((F == '>' || F == GE) && equals(ARG(0,condition),a) && equals(ARG(1,condition),h))
leftu = ARG(1,ARG(i,u));
else if((F == '<' || F == LE) && equals(ARG(0,condition),a) && equals(ARG(1,condition),h))
rightu = ARG(1,ARG(i,u));
else if((F == '>' || F == GE) && equals(ARG(1,condition),a) && equals(ARG(0,condition),h))
rightu = ARG(1,ARG(i,u));
}
if(FUNCTOR(leftu) != ILLEGAL)
{ err2 = limval_aux(topcall, n==2 ? limit(ARG(0,t),leftu) : limit3(ARG(0,t),ARG(1,t),leftu), &ansleft,&l1,&r1);
if(err2)
return 1;
if(n == 3 && equals(ARG(1,t),left))
{ *ans = ansleft;
*l = l1;
*r = r1;
return 0;
}
}
if(FUNCTOR(rightu) != ILLEGAL)
{ err2 = limval_aux(topcall, n==2 ? limit(ARG(0,t),rightu) : limit3(ARG(0,t),ARG(1,t),rightu), &ansright,&l2,&r2);
if(err2)
return 1;
if(n == 3 && equals(ARG(1,t),right))
{ *ans = ansright;
*l = l2;
*r = r2;
return 0;
}
}
if(FUNCTOR(leftu) != ILLEGAL && FUNCTOR(rightu) != ILLEGAL && n == 2)
{ /* Now we've computed both left and right limits */
*l = l1;
*r = r2;
if(equals(ansleft,ansright))
{ *ans = ansleft;
return 0;
}
else
{ /* this is a jump discontinuity (or worse if *ansleft or *ansright is infinite) */
*ans = undefined;
return 0;
}
}
/* we get here if the CASES split was at some other point than where we're now taking
the limit. In that case, just fall through */
}
leadingterm: /* get here from two loops deep in previous 30 lines or so */
if(topcall)
err = leading_term1(u,h,a,&c,&d);
/* answer c == 0 is acceptable */
else
err = leading_term(u,h,a,&c,&d);
if(err == 2)
{ *ans = undefined;
reset_heap(savenode);
set_nvariables(nvars);
return 2; /* domain error */
}
if(!err)
{ err = finish_from_leading_term(topcall,u,h,a,c,d,n,dir,ans,l,r);
if(err)
{ reset_heap(savenode);
set_nvariables(nvars);
return err;
}
save_and_reset(*ans,savenode,ans);
return 0;
}
/* Now try inverting: change limits at infinity to limits at zero.
But don't do this if it will create an e^(1/x) term as these are
intractable and even lead to loops sometimes */
if(
(equals(a,infinity) || equals(a,minusinfinity)) &&
!contains(u,DIFF) && /* you have to evaluate the derivatives first */
/* otherwise you get a term diff(u,1/h) which
is meaningless and causes a crash */
!contains_exp(u,h) /* reject e^h etc. but accept e^(1/h) */
)
{ subst(make_fraction(one,h),h,u,&mid);
save_and_reset(limit3(arrow(h,zero),equals(a,infinity) ? right : left,mid),savenode,&temp);
err = limval_aux(topcall,temp,ans,r,l);
/* limits at infinity reduce to one-sided limits at zero, even
when using complex numbers, e.g.
lim(x->inf,x) = lim(x->0+,1/x) = infinity */
if(err)
{ reset_heap(savenode);
set_nvariables(nvars);
return err;
}
save_and_reset(*ans,savenode,ans);
return 0;
}
/* Next try the squeeze theorem: for example u = x sin(1/x) */
if(f=='*' || f=='/')
{ if (contains(u,SIN) || contains(u,COS))
{ err = squeeze_theorem_aux(t,&next); /* next is irrelevant here */
if(!err)
{ *ans = zero;
save_and_reset(*ans,savenode,ans);
set_nvariables(nvars);
return 0;
}
}
/* Well, the squeeze theorem didn't help. */
if(FRACTION(u))
{ reset_heap(savenode);
return 1; /* give up */
}
/* But if u is a product, we have one more thing to try:
Example: x ln x = (ln x)/(1/x)
This is dealt with by 'createcompoundfraction' on the menus;
we use its auxiliary function here: */
save_and_reset(u,savenode,&u);
/* although the original u lived below savenode, it was
reassigned and now lives above savenode. */
err = special_exponential_limit(topcall,t,ans,l,r);
if(!err)
return 0;
save_and_reset(u,savenode,&u);
err = select_ccfarg(u,h,&num,&d);
if(!err)
{ if(contains(d,'/'))
polyval(reciprocal(d),&denom);
else
denom = reciprocal(d);
mid = make_fraction(num,denom);
SET_ALREADY(mid); /* otherwise polyval will remove the
compound fraction we just created */
dd = n==2 ? limit(ARG(0,t),mid) : limit3(ARG(0,t),ARG(1,t),mid);
err = limval_aux(topcall,dd,ans,l,r);
if(err == 2)
{ *ans = undefined;
reset_heap(savenode);
set_nvariables(nvars);
return 2;
}
if(!err)
{ save_and_reset(*ans,savenode,ans);
return 0;
}
}
}
reset_heap(savenode);
set_nvariables(nvars);
return 1; /* failure */
}
/*___________________________________________________________________________________*/
static int special_exponential_limit(int topcall,term t, term *ans, approach *l, approach *r)
/* Now catch lim (x->0+, g(x) e^(b/x) ) and f has a leading term,
and also lim(x->0+, g(x)/e^(b/x) or e^(b/x)/g(x) or just e^(b/x).
Presumes t is a limit term.
*/
{ unsigned n,f;
term u,h,a,c,d,p,q,rr,c1,d1,A,B;
unsigned short dir;
int err;
int flip = 0;
n = ARITY(t);
assert(FUNCTOR(ARG(0,t))==ARROW);
h = ARG(0,ARG(0,t)); /* the limit variable */
if(!ISATOM(h))
assert(0);
a = ARG(1,ARG(0,t));
if(!ZERO(a))
return 1;
if(n==2)
u = ARG(1,t); /* so t = lim(h->a,u) */
else
{ u = ARG(2,t);
dir = equals(ARG(1,t),left) ? LEFTDIR : RIGHTDIR;
}
if(ARITY(u) != 2)
return 1;
f = FUNCTOR(u);
if(f != '*' && f != '/')
return 1;
if(FUNCTOR(ARG(0,u)) == '^' && equals(ARG(0,ARG(0,u)),eulere))
{ A = ARG(0,u);
B = ARG(1,u);
}
else if(FUNCTOR(ARG(1,u)) == '^' && equals(ARG(0,ARG(1,u)),eulere))
{ B = ARG(0,u);
A = ARG(1,u);
flip = 1;
}
else
return 1;
if(!FRACTION(ARG(1,A)))
return 1;
p = ARG(0,ARG(1,A));
q = ARG(1,ARG(1,A)); /* So A = e^(p/q) */
rr = make_fraction(q,p);
err = leading_term(rr,h,a,&c,&d);
if(err || !obviously_nonzero(d) || !obviously_nonzero(c))
return 1;
// A goes to infinity very strongly at zero, so the sign of d doesn't matter
err = leading_term(B,h,a,&c1,&d1);
if(err || !obviously_nonzero(c1))
return 1;
// we're going to get an answer, unless the sign of c1 is indeterminate
if(n==2 && topcall)
{ *ans = undefined;
return 0;
}
if(f == '*' || (!flip && topcall))
{ *ans = infinity;
return 0;
}
if(obviously_positive(c1))
{ if(f == '*' || !flip)
{ *r = max;
*l = min;
if(n==3 && dir == RIGHTDIR)
*ans = infinity;
else if(n==3 && dir == LEFTDIR)
*ans = zero;
else if(n==2)
*ans = undefined;
else
assert(0);
return 0;
}
if(f == '/' && flip) // lim 1/e^(1/x)
{ *r = min;
*l = max;
if(n==3 && dir == LEFTDIR)
*ans = infinity;
else if(n==3 && dir == RIGHTDIR)
*ans = zero;
else if(n==2)
*ans = undefined;
else
assert(0);
return 0;
}
else
assert(0);
}
if(obviously_negative(c1))
{ if(f == '*' || !flip)
{ *r = min;
*l = max;
if(n==3 && dir == RIGHTDIR)
*ans = minusinfinity;
else if(n==3 && dir == LEFTDIR)
*ans = zero;
else if(n==2)
*ans = undefined;
else
assert(0);
return 0;
}
if(f == '/' && flip) // lim -1/ e^(1/x)
{ *r = max;
*l = min;
if(n==3 && dir == LEFTDIR)
*ans = minusinfinity;
else if(n==3 && dir == RIGHTDIR)
*ans = zero;
else if(n==2)
*ans = undefined;
else
assert(0);
return 0;
}
else
assert(0);
}
return 1;
}
/*________________________________________________________________________*/
static int limval_by_composition(term t, term *ans)
/* compute the limit by composition.
Example, limit of sin(sqrt t)/sqrt(t).
Return 0 for success, 1 for failure of maximal_sub,
2 if maximal_sub works but the resulting limits can't be computed.
*/
{ approach l,r;
int savenvariables = get_nvariables();
int savenextdefn = get_nextdefn();
int saveeigen = get_eigenindex();
short savenextassumption = get_nextassumption();
term sub,w,b,newvar,mid;
unsigned short n = ARITY(t);
term u = LIMITAND(t);
int err = maximal_sub(u,&sub);
if(err)
return 1;
w = n==2 ? limit(ARG(0,t),sub) : limit3(ARG(0,t),ARG(1,t),sub);
fillbinders(w);
err = limval_aux(0,w,&b,&l,&r);
releasebinders();
if(err)
return 2;
newvar = getnewvar(u,"uvwpqst");
subst(newvar,sub,u,&mid);
/* Now we have to compute the limit of mid as newvar->b,
but do we need to compute a one-sided or two-sided limit? */
if(ISINFINITE(b))
{ w = limit(arrow(newvar,b),mid);
goto out;
}
if(NOTDEFINED(b))
{ set_nvariables(savenvariables);
set_eigenvariable(saveeigen);
set_nextdefn(savenextdefn);
return 2;
}
if(n == 2)
{ /* original limit is two-sided, so both l and r should
have sensible values */
if(l == r && l == max)
w = limit3(arrow(newvar,b),left,mid);
else if(l == r && l == min)
w = limit3(arrow(newvar,b),right,mid);
else
w = limit(arrow(newvar,b),mid);
goto out;
}
/* original limit was one-sided, so one of l or r may be garbage. */
if(equals(ARG(1,t),left))
{ if(l == max)
w = limit3(arrow(newvar,b),left,mid);
else if (l == min)
w = limit3(arrow(newvar,b),right,mid);
else if (l == bounded_oscillation)
w = limit(arrow(newvar,b),mid);
goto out;
}
if(equals(ARG(1,t),right))
{ if(r == max)
w = limit3(arrow(newvar,b),left,mid);
else if (r == min)
w = limit3(arrow(newvar,b),right,mid);
else if (r == bounded_oscillation)
w = limit(arrow(newvar,b),mid);
goto out;
}
return 2;
out:
err = limval(w,ans);
set_nvariables(savenvariables);
set_nextdefn(savenextdefn);
set_eigenvariable(saveeigen);
set_nextassumption(savenextassumption);
return err ? 2 : 0;
}
/*_________________________________________________________________*/
int limval(term t, term *ans)
/* evaluate the limit term t, eliminating the functor LIMIT at
toplevel, but using only elementary means, if possible. The term
*ans may still contain LIMIT somewhere afterwards.
Zero return is success (in eliminating the toplevel LIMIT).
The returned *ans can be a defined term or one of the undefined atoms:
infinity, minusinfinity, undefined, bounded_oscillations, unbounded_oscillations.
So just because this function succeeds doesn't mean the
answer is defined.
Return value 1 means failure to eliminate the toplevel LIMIT, not failure
to be defined. In this case *ans is not garbage, but t itself.
Return value 2 means the limit is undefined due to domain error, that is,
the limit point is not in the closure of the domain of the limitand.
*/
{ int err;
approach l,r;
int save_functionflag, save_zeropowerflag, save_gcdflag,save_factorflag2,
save_logflag, save_fractexpflag, save_negexpflag, save_comdenomflag,
save_factorflag;
err = badlimit(t); /* check for limits we know we can't do */
if(!err)
{ *ans = t;
return 1;
}
err = limval_by_composition(t,ans);
if(!err)
return 0;
if(err == 2)
{ *ans = t;
return 2; /* cut your losses. If maximal_sub works and you can't
compute the resulting limits, nothing to be tried below will work either. */
}
fillbinders(t);
save_functionflag = get_polyvalfunctionflag();
save_zeropowerflag = get_polyvalzeropowerflag();
save_factorflag = get_polyvalfactorflag();
save_gcdflag = get_polyvalgcdflag();
save_factorflag2 = get_polyvalfactorflag2();
save_logflag = get_polyvallogflag();
save_fractexpflag = get_polyvalfractexpflag();
save_negexpflag = get_polyvalnegexpflag();
save_comdenomflag = get_polyvalcomdenomflag();
save_factorflag = get_polyvalfactorflag();
set_polyvalfunctionflag(1);
set_polyvalgcdflag(1);
set_polyvalzeropowerflag(1);
set_polyvalfractexpflag(1);
set_polyvalcomdenomflag(1);
set_polyvalfunctionflag(1);
set_polyvalfactorflag2(0x011); /* factor nums and denoms only */
set_polyvalfactorflag(1); /* content_factoring is OK */
set_polyvallogflag(1); /* perform only e^log x = x etc., not log collection */
set_polyvalnegexpflag(0);
set_lhopital_depth(0);
if(save_gcdflag != 1 || save_zeropowerflag != 1 || save_fractexpflag != 1 || save_comdenomflag != 1 || save_factorflag != 1 ||
save_factorflag2 != 0x011 || save_logflag != 1 || save_functionflag != 1 || save_gcdflag != 1 || save_negexpflag != 0)
clear_already(&t);
err = limval_aux(1,t,ans,&l,&r);
set_polyvalfunctionflag(save_functionflag);
set_polyvalgcdflag(save_gcdflag);
set_polyvalzeropowerflag(save_zeropowerflag);
set_polyvalfactorflag(save_factorflag);
set_polyvalfactorflag2(save_factorflag2);
set_polyvalfractexpflag(save_fractexpflag);
set_polyvalnegexpflag(save_negexpflag);
set_polyvalcomdenomflag(save_comdenomflag);
set_polyvallogflag(save_logflag);
set_polyvalfactorflag(save_factorflag);
if(err == 2)
{ *ans = undefined;
releasebinders();
return 2;
}
if(err)
{ /* Maybe it's a complicated rational expression. Try reducing
it to canonical rational form as a quotient of polynomials
before giving up.
*/
POLYnomial polynum,polydenom;
term x,u,v;
unsigned short n = ARITY(t);
x = ARG(0,ARG(0,t));
err = make_polyquo(LIMITAND(t),x,&polynum,&polydenom);
if(err)
{ *ans = t;
releasebinders();
return 1;
}
u = make_fraction(poly_term(polynum,x),poly_term(polydenom,x));
SET_ALREADY(u); /* don't put it through polyval again, this can
cause an out-of-space error in polygcd, and
besides it's going to be fruitless since
make_polyquo has returned a rational function
in lowest terms. */
v = n==3 ? limit3(ARG(0,t),ARG(1,t),u) : limit(ARG(0,t),u);
releasebinders();
if(equals(v,t))
{ *ans = t;
return 1;
}
return limval(v,ans);
}
releasebinders();
return 0;
}
/*___________________________________________________________________*/
int squeeze_theorem_aux(term t, term *next)
/* t is a limit term whose limitand is a product containing SIN or COS,
or a fraction whose numerator is SIN or COS or is a product
which contains SIN or COS or a power of them, or a sum one of
whose summands is SIN or COS or a product containing SIN or COS
as a factor, whose other summands are bounded in the limit.
Remove all factors of sin or cos, and if the remaining limit goes
to zero return 0 for success, with *next = the remaining limit.
If flag is nonzero,
you don't have to return the approach styles *l and *r for the limit of t;
but if it is zero, you must calculate these by calculating the limits
of the args of sin and cos. If this can't be done return 1. */
{ unsigned short n = ARITY(t);
term u = LIMITAND(t);
unsigned short f = FUNCTOR(u);
term v,w,temp,denom,ans;
unsigned short m,k;
int i,err;
if(f == '/')
{ denom = ARG(1,u);
u = ARG(0,u);
}
else
denom = one;
f = FUNCTOR(u);
if(f == SIN || f == COS)
{ if(ONE(denom))
return 1;
v = one;
}
else if(f == '+' && !ONE(denom) && oscillatory(t,u))
v = one;
else if(f != '*')
return 1;
else /* if(f == '*') */
{ m = ARITY(u);
v = make_term('*',m);
k = 0;
/* build v as a product of the non-oscillatory factors */
for(i=0;i<m;i++)
{ w = ARG(i,u);
if(!oscillatory(t,w))
{ ARGREP(v,k,w);
++k;
}
}
if(k==m)
{ RELEASE(v);
return 1;
}
if(k==0)
{ RELEASE(v);
return 1;
}
if(k==1)
{ temp = ARG(0,v);
RELEASE(v);
v = temp;
}
else
SETFUNCTOR(v,'*',k);
}
if(!ONE(denom))
v = make_fraction(v,denom);
temp = n==2 ? limit(ARG(0,t),v) : limit3(ARG(0,t),ARG(1,t),v);
err = limval(temp,&ans);
if(err || !ZERO(ans))
return 1;
*next = temp;
return 0;
}
/*_________________________________________________________________*/
static approach approach_aux(approach a, approach b)
/* a and b are the style of approach of numerator and denom of a
quotient of limits. Suppose the lim of the denom is finite and
nonzero and that of the num is finite.
Return the style of approach of the quotient (which can be 'unknown').
*/
{ if(a == unknown || b == unknown)
return unknown;
if(a == min && b == max)
return min;
if(a == max && b == min)
return min;
return unknown;
}
/*_____________________________________________________________________*/
int select_ccfarg(term uv, term x, term *num, term *arg)
/* select the arg of createcompoundfraction in auto mode */
/* that is, in doing lim(x->a, uv), which factor or factors of uv should be
moved to the denom? Examples:
if uv is x ln u, move x to the denom (isolate ln)
if uv is x e^u, move e^u to the denom.
if uv is x^(-n) e^u, move x^(-n) to the denom.
If uv is x 2^(4-x), move 2^-x to the denom
if one factor is a trig function of u, or a power of a trig function
of u, and u is linear in x, move it to the denom. But don't do
this if u is not linear in x, e.g. lim(x->infinity x sin(1/x))
should not be converted to x/csc(1/x).
In menu mode there are several operators that do not require
an arg: isolateln, isolatelnpower, exptodenom, negexptodenom,
trigtodenom.
Return 1 for failure, 0 for success.
*/
{ unsigned short n = ARITY(uv);
int i,err;
term w,cancelled;
unsigned short f;
int logflag, negpowerflag, expflag, tflag;
if(FUNCTOR(uv) != '*')
return 1;
/* first determine if there is a log term (or power of one),
a negative power of x,
a trig function (or power of one) or an exponential */
logflag = negpowerflag = expflag = tflag = 0;
for(i=0;i<n;i++)
{ w = ARG(i,uv);
f = FUNCTOR(w);
if(f == LN)
logflag = i+1;
else if(f == '^' && FUNCTOR(ARG(0,w)) == LN)
logflag = i+1; /* notice ln^n x as well as ln x */
else if(f == '^' && equals(ARG(0,w),eulere) && !constant(ARG(1,w)))
{ if(FRACTION(ARG(1,w)) && !constant(ARG(1,ARG(1,w))))
return 1; // then inversion isn't going to help
else
expflag = i+1;
}
else if(f == '^' && equals(ARG(0,w),x) && NEGATIVE(ARG(1,w)))
negpowerflag = i+1;
else if(f == '^' && FUNCTOR(ARG(1,w)) == '+')
{ // x 2^(4-x) for example
int mm = ARITY(ARG(1,w));
for(int ell = 0; ell < mm; ell++)
{ if(NEGATIVE(ARG(ell,ARG(1,w))))
negpowerflag = i+1;
}
}
else if(TRIGFUNCTOR(f) && is_linear_in(ARG(0,w),x))
tflag = i+1;
else if(f == '^' && TRIGFUNCTOR(FUNCTOR(ARG(0,w))) && is_linear_in(ARG(0,w),x))
tflag = i+1;
}
if(logflag)
{ *num = ARG(logflag-1,uv);
err = cancel(uv,*num,&cancelled,arg);
if(err)
assert(0);
return 0;
}
if(negpowerflag) /* in x^-3 e^x it's the x^-3 that should move */
{ *arg = ARG(negpowerflag-1,uv);
err = cancel(uv,*arg,&cancelled,num);
if(err)
assert(0);
return 0;
}
if(expflag) /* in x^3 e^x it's the e^x that should move */
{ *arg = ARG(expflag-1,uv);
err = cancel(uv,*arg,&cancelled,num);
if(err)
assert(0);
return 0;
}
if(tflag)
{ *arg = ARG(tflag-1,uv);
err = cancel(uv,*arg,&cancelled,num);
assert(!err);
return 0;
}
return 1;
}
/*_________________________________________________________________*/
static int limlinear2(term t,term *next)
/* reason-free version of limlinear that assumes the limitand is
a product or quotient and that the limitand isn't constant */
{ term z,x,c,d,w,u,v,mid;
unsigned short n = ARITY(t);
if(FUNCTOR(t) != LIMIT)
return 1;
z = LIMITAND(t);
x = ARG(0,ARG(0,t));
if(FUNCTOR(z)=='/' && !depends(ARG(1,z),x))
{ if(ONE(ARG(1,z)))
return 1;
c = make_fraction(one,ARG(1,z));
HIGHLIGHT(c);
*next = signedproduct(c,n==2 ? limit(ARG(0,t),ARG(0,z)) : limit3(ARG(0,t),ARG(1,t),ARG(0,z)));
return 0;
}
if(FUNCTOR(z)=='/' && !depends(ARG(0,z),x))
{ if(ONE(ARG(0,z)))
return 1;
mid = make_fraction(one,ARG(1,z));
c = ARG(0,z);
HIGHLIGHT(c);
*next = product(c,n==2 ? limit(ARG(0,t),mid) : limit3(ARG(0,t),ARG(1,t),mid));
return 0;
}
if(FUNCTOR(z)=='/' && (FUNCTOR(ARG(1,z))=='*' || FUNCTOR(ARG(0,z))=='*'))
{ if(FUNCTOR(ARG(1,z))=='*')
twoparts(ARG(1,z),x,&c,&v);
else
{ c = one;
v = ARG(1,z);
}
if(FUNCTOR(ARG(0,z)) =='*')
twoparts(ARG(0,z),x,&d,&w);
else
{ d = one;
w = ARG(0,z);
}
if(ONE(c) && ONE(d))
return 1;
u = make_fraction(w,v);
mid = n==2 ? limit(ARG(0,t),u) : limit3(ARG(0,t),ARG(1,t),u);
c = make_fraction(d,c);
HIGHLIGHT(c);
*next = signedproduct(c,mid);
return 0;
}
if(FUNCTOR(z) != '*')
return 1;
/* Now pull out the factors that don't depend on x. Can't use ncs
here as there may be other variables that nevertheless don't depend on x */
twoparts(z,x,&c,&u);
if(ONE(c))
return 1;
if( n == 2)
*next = product(c,limit(ARG(0,t),u));
else
*next = product(c,limit3(ARG(0,t),ARG(1,t),u));
if(FUNCTOR(c)=='*')
RELEASE(c); /* see documentation of twoparts in pvalaux.c */
HIGHLIGHT(*next);
return 0;
}
/*_____________________________________________________*/
static int divnumdenom3(int topcall,term t, term arg, term *ans, approach *l, approach *r)
/* reason-free, model-free version of divnumdenom */
/* divide num and denom in a limit of quotients by arg and
then, if topcall is nonzero, evaluate the limits, returning the
answer in *ans. If topcall is zero, return a quotient of limits
or a limit. */
{ term u,v,c,d,newnum,newdenom,cc,dd;
approach lu,lv,ru,rv;
int err;
unsigned short n;
if(FUNCTOR(t) != LIMIT)
return 1;
n = ARITY(t);
u = LIMITAND(t);
if(FUNCTOR(arg) == ILLEGAL)
{ err = select_divnumdenom_arg(t,&arg);
if(err)
return 1;
}
c = make_fraction(ARG(0,u),arg);
if(FUNCTOR(ARG(0,u)) == '+')
err = apart3(c,&cc);
else
err = polyval(make_fraction(ARG(0,u),arg),&cc);
if(err)
cc = c;
else
SET_ALREADY(cc); /* limval calls polyval; without this it will
undo what apartandcancel did, and cause a loop */
if(equals(arg,ARG(1,u)) && !err) /* example u = (5+x)/x */
{ *ans = n==2 ? limit(ARG(0,t),cc) : limit3(ARG(0,t),ARG(1,t),cc);
return 0;
}
d = make_fraction(ARG(1,u),arg);
if(FUNCTOR(ARG(1,u)) == '+')
err = apart3(d,&dd);
else
err = polyval(make_fraction(ARG(1,u),arg),&dd);
/* Not just cancel as e.g. sqrt(u)/u^(1/2) must be simplified */
if(err)
dd = d;
else
SET_ALREADY(dd); /* limval calls polyval; without this it will
undo what apartandcancel did, and cause a loop.
Actually, this is ineffective, as polyval calls
UNSET_ALREADY and uses common denoms anyway,
when working on fractions.
*/
if(equals(cc,u) || equals(dd,u))
return 1; /* stop a potential loop */
newnum = n==2 ? limit(ARG(0,t),cc) : limit3(ARG(0,t),ARG(1,t),cc);
newdenom = n==2 ? limit(ARG(0,t),dd) : limit3(ARG(0,t),ARG(1,t),dd);
if(topcall)
{ err = limval(newdenom,&v);
if(err)
return 1;
if(ZERO(v))
goto tryharder;
err = limval(newnum,&u);
if(err)
return 1;
return finish_limquo(u,v,ans);
}
else
{ tryharder:
err = limval_aux(0,newdenom,&v,&lv,&rv);
if(err)
return 1;
err = limval_aux(0,newnum,&u,&lu,&ru);
if(err)
return 1;
return finish_limquo2(u,lu,ru,v,lv,rv,ans,l,r);
}
}
/*___________________________________________________________________________*/
static int finish_limquo(term u, term v, term *ans)
/* a quotient of limits has evaluated to u/v. Finish the limit evaluation
if possible, returning 0 for success. Return 1 for failure.
*/
{ if(!NOTDEFINED(u) && !NOTDEFINED(v))
{ polyval(make_fraction(u,v),ans);
return 0;
}
if(!NOTDEFINED(u) && ISINFINITE(v))
{ *ans = zero;
return 0;
}
if(!NOTDEFINED(v) && ISINFINITE(u))
{ if(obviously_nonnegative(v))
{ *ans = u;
return 0;
}
if(obviously_nonnegative(strongnegate(v)))
{ *ans = tnegate(u);
return 0;
}
if(!infer(le(zero,v)))
{ *ans = u;
return 0;
}
if(!infer(le(v,zero)))
{ *ans = tnegate(u);
return 0;
}
*ans = undefined;
return 0;
}
if(!NOTDEFINED(v) && equals(u,unbounded_oscillations))
{ *ans = unbounded_oscillations;
return 0;
}
if(!NOTDEFINED(v) && equals(u,bounded_oscillations))
{ if(!infer(nonzero(v)))
{ *ans = bounded_oscillations;
return 0;
}
*ans = undefined;
return 0;
}
if(!NOTDEFINED(v))
{ *ans = undefined;
return 0;
}
if(!NOTDEFINED(u) && ISINFINITE(v))
{ *ans = zero;
return 0;
}
if(ISINFINITE(v) && equals(u,bounded_oscillations))
{ *ans = zero;
return 0;
}
return 1;
}
/*___________________________________________________________________________*/
static int finish_limquo2(term u, approach lu, approach ru,
term v, approach lv, approach rv,
term *ans, approach *l, approach *r)
/* a quotient of limits has evaluated to u/v. Finish the limit evaluation
if possible, returning 0 for success. Return 1 for failure.
The approaches to the limits u and v are given in lu,ru,lv,rv;
for success, we require a successful computation of the approaches *l and *r
to the answer *ans, except in case *ans is 'undefined'.
*/
{ int err;
if(NOTDEFINED(v) || ZERO(v))
return 1;
if(!NOTDEFINED(u))
{ polyval(make_fraction(u,v),ans);
*l = approach_aux(lu,lv);
if(*l == unknown)
return 1;
*r = approach_aux(ru,rv);
if(*r == unknown)
return 1;
return 0;
}
/* Now u is NOTDEFINED */
switch(FUNCTOR(u))
{ case UNDEFINED:
*ans = undefined;
return 0;
case BOUNDED_OSCILLATIONS: /* fall-through */
case UNBOUNDED_OSCILLATIONS:
*ans = u;
*l = lu;
*r = ru;
return 0;
}
if(!equals(u,infinity) && !equals(u,minusinfinity))
assert(0);
err = infer(lessthan(zero,v));
if(!err)
{ *ans = u;
*l = lu;
*r = ru;
return 0;
}
err = infer(lessthan(v,zero));
if(!err)
{ *ans = tnegate(u);
*l = REVERSE(lu);
*r = REVERSE(ru);
return 0;
}
*ans = undefined; /* can't determine sign of denval */
return 0;
}
/*__________________________________________________________________*/
int select_pnzarg(term t,term *arg, term *mid)
/* t is a limit of a quotient;
arg * mid = the limitand of t, where arg contains all factors of
either num or denom that go to nonzero finite limits. */
/* Return 0 if a non-trival such arg was found and not ALL the factors
had defined nonzero limits. */
{ unsigned short n = ARITY(t);
unsigned short m,k,j,g;
int i,err;
int save_lhopital_depth = get_lhopital_depth();
term u,v,w,arg1,arg2,mid1,mid2,temp,num,denom,power,x,a,b,trash,newpower;
u = LIMITAND(t);
x = ARG(0,ARG(0,t));
if(FUNCTOR(u)=='/')
{ num = ARG(0,u);
denom = ARG(1,u);
temp = n==2 ? limit(ARG(0,t),num) : limit3(ARG(0,t),ARG(1,t),num);
select_pnzarg(temp,&arg1,&mid1);
temp = n==2 ? limit(ARG(0,t),denom) : limit3(ARG(0,t),ARG(1,t),denom);
select_pnzarg(temp,&arg2,&mid2);
*arg = make_fraction(arg1,arg2);
polyval(make_fraction(mid1,mid2),mid);
if(!ONE(*arg))
{ SET_ALREADY(*arg);
return 0;
}
/* Now work harder: look for (sin x) /x to pull out, or (tan x)/x */
if((FUNCTOR(num)==SIN || FUNCTOR(num) == TAN) && !ATOMIC(num))
{ v = ARG(0,num);
g = FUNCTOR(num);
power = one;
}
else if(FUNCTOR(num) == '^' && (FUNCTOR(ARG(0,num)) == SIN || FUNCTOR(ARG(0,num))==TAN))
{ v = ARG(0,ARG(0,num));
power = ARG(1,num);
g = FUNCTOR(ARG(0,num));
}
else if(FUNCTOR(num) == '*')
{ for(i=0;i<ARITY(num);i++)
{ if(FUNCTOR(ARG(i,num))==SIN || FUNCTOR(ARG(i,num))==TAN)
{ v = ARG(0,ARG(i,num));
power = one;
g = FUNCTOR(ARG(i,num));
break;
}
if(FUNCTOR(ARG(i,num)) == '^' &&
(FUNCTOR(ARG(0,ARG(i,num))) == SIN ||
FUNCTOR(ARG(0,ARG(i,num))) == TAN
)
)
{ v = ARG(0,ARG(0,ARG(i,num)));
power = ARG(1,ARG(i,num));
g = FUNCTOR(ARG(0,ARG(i,num)));
break;
}
}
if(i==ARITY(num))
return 1;
}
else
return 1;
err = limval(n==2 ? limit(ARG(0,t),v) : limit3(ARG(0,t),ARG(1,t),v),&temp);
set_lhopital_depth(save_lhopital_depth);
if(err || !ZERO(temp))
return 1;
if(FUNCTOR(num) != SIN && FUNCTOR(num) != TAN)
{ twoparts(v,x,&mid1,&mid2);
v = mid2; /* drop constant parts */
/* but don't do this e.g. on lim(t->0, sin(3t)/t^(1/2)), where
we now have v = 3t and must keep it so */
}
if(!ONE(power))
{ err = cancel(denom,make_power(v,power),&mid1,&temp);
if(!err && FUNCTOR(temp) != '/')
{ w = g==SIN ? sin1(v) : tan1(v);
w = make_power(w,power);
*arg = make_fraction(w,make_power(v,power));
err = cancel(num,w,&mid1,&mid2);
if(err)
return 1;
*mid = make_fraction(mid2,temp);
if(ONE(*mid) || ONE(*arg))
return 1;
SET_ALREADY(*arg);
return 0;
}
if(FUNCTOR(temp)=='/')
err = 1; /* so we enter next if */
}
if(ONE(power) || err) /* if can't cancel out sin^n t then cancel out sin t */
{ err = cancel(denom,v,&mid1,&temp);
if(err)
return 1;
w = g==SIN ? sin1(v) : tan1(v);
*arg = make_fraction(w,v);
err = cancel(num,w,&mid1,&mid2);
if(err)
return 1;
polyval(make_fraction(mid2,temp),mid);
if(!contains(*mid, FUNCTOR(x)) || !contains(*arg,FUNCTOR(x)))
return 1; /* don't just be pulling out a constant */
SET_ALREADY(*arg);
return 0;
}
}
if(FUNCTOR(u) != '*' && FUNCTOR(u) != '/')
{ err = limval(t,&temp);
set_lhopital_depth(save_lhopital_depth);
if(err || ZERO(temp) || NOTDEFINED(temp) ||
!infer(equation(temp,zero)) // temp might still be actually zero even though limval didn't discover that
)
{ *mid = u;
*arg = one;
}
else
{ *mid = one;
*arg = u;
}
return 1;
}
/* Now u is a product */
m = ARITY(u);
*arg = make_term('*',m);
*mid = make_term('*',m);
k = j = 0;
for(i=0;i<m;i++)
{ v = n==2 ? limit(ARG(0,t),ARG(i,u)) : limit3(ARG(0,t),ARG(1,t),ARG(i,u));
err = limval(v,&temp);
set_lhopital_depth(save_lhopital_depth);
if(err || ZERO(temp) || NOTDEFINED(temp))
{ ARGREP(*mid,j,ARG(i,u));
++j;
}
else
{ ARGREP(*arg,k,ARG(i,u));
++k;
}
RELEASE(v);
}
if(k==0) /* no nonzero finite limits found */
{ RELEASE(*arg);
if(contains(u,CSC))
{ /* look for x csc(x) to take out, or x^n csc^n x */
for(i=0;i<m;i++)
{ if(equals(ARG(i,u),x))
break;
if(FUNCTOR(ARG(i,u)) == '^' &&
equals(ARG(0,ARG(i,u)),x) &&
ISINTEGER(ARG(1,ARG(i,u)))
)
break;
}
if(i==m)
{ *arg = one;
return 1;
}
for(j=0;j<m;j++)
{ if(FUNCTOR(ARG(j,u)) == CSC && equals(ARG(0,ARG(j,u)),x))
break;
if(FUNCTOR(ARG(j,u)) == '^' &&
FUNCTOR(ARG(0,ARG(j,u))) == CSC &&
ISINTEGER(ARG(1,ARG(j,u))) &&
equals(ARG(0,ARG(0,ARG(j,u))),x)
)
break;
}
if(j==m)
{ *arg = one;
return 1;
}
/* Now we have x or a power of it in ARG(i,u), and
csc(x) or a power of it in ARG(j,u) */
a = ARG(i,u);
b = ARG(j,u);
if(FUNCTOR(a) != '^' || FUNCTOR(b) != '^')
{ /* then just take out x csc x */
*arg = product(x,csc1(x));
err = cancel(u,*arg,&trash,mid);
if(err)
{ /* assert(0); */
*arg = one;
return 1;
}
return 0;
}
if(INTDATA(ARG(1,a)) <= INTDATA(ARG(1,b)))
copy(ARG(1,a),&newpower);
else
copy(ARG(1,b),&newpower);
*arg = product(make_power(x,newpower), make_power(csc1(x),newpower));
err = cancel(u,*arg,&trash,mid);
if(err)
{ /* assert(0); */
*arg = one;
return 1;
}
return 0;
}
*arg = one;
/* *mid is ok */
return 1;
}
if(j==0) /* ALL limits were nonzero and finite */
{ RELEASE(*mid);
*mid = one;
return 1;
}
if(k==1)
{ temp = ARG(0,*arg);
RELEASE(*arg);
*arg = temp;
}
else
SETFUNCTOR(*arg, '*', k);
if(j==0)
{ RELEASE(*mid);
*mid = one;
}
else if (j==1)
{ temp = ARG(0,*mid);
RELEASE(*mid);
*mid = temp;
}
else
SETFUNCTOR(*mid,'*',j);
return 0;
}
/*__________________________________________________________________*/
static int pnz2(term t, term *next)
/* reason-free version of pulloutnonzerolimit, which
selects its own arg as pulloutnonzerolimit does in automode,
for use in limval */
{ unsigned short n;
int err;
term arg;
term p,q,mid;
if(FUNCTOR(t) != LIMIT)
return 1;
n = ARITY(t);
p = LIMITAND(t);
if(FUNCTOR(p) != '/')
return 1;
err = select_pnzarg(t,&arg,&mid);
if(err || ONE(mid) || ONE(arg))
return 1;
q = n==2 ? limit(ARG(0,t),mid) : limit3(ARG(0,t),ARG(1,t),mid);
p = n==2 ? limit(ARG(0,t),arg) : limit3(ARG(0,t),ARG(1,t),arg);
*next = product(p,q);
return 0;
}
/*___________________________________________________________________*/
static int ppoly(term t, term x)
/* Return 0 if t is a 'ppoly' of x, that is, a polynomial in
a root, sqrt, or power of x, or a product of ppolys.
Return 0 for success, 1 for failure. */
{ unsigned short f = FUNCTOR(t);
unsigned short n;
term c;
int i;
if(ATOMIC(t))
return 0;
if(f == SQRT)
return ppoly(ARG(0,t),x);
if(f == ROOT && !contains(ARG(0,t),FUNCTOR(x)))
return ppoly(ARG(1,t),x);
if(f == '^' && equals(ARG(0,t),x) && !contains(ARG(1,t),FUNCTOR(x)))
return ppoly(ARG(0,t),x);
if(f == '-')
return ppoly(ARG(0,t),x);
if(f != '+' && f != '*')
return 1;
n = ARITY(t);
for(i=0;i<n;i++)
{ c = ARG(i,t);
if(!contains(c,FUNCTOR(x)))
continue;
if(ppoly(c,x)==1)
return 1;
}
return 0;
}
/*___________________________________________________________________*/
int select_divnumdenom_arg(term t,term *arg)
/* given a quotient u and the problem t = lim(x->a,u), return in *arg
something which we should divide num and denom by.
Examples (for the case a = infinity):
1. if u is a rational function, choose the leading power
in the denominator.
2. If the num and denom are polynomials in some root or power of x,
as in (1+ sqrt x)/(1- sqrt x), choose the leading term of the denom.
3. If the denom has the form sqrt u \pm v where v is as in 1. or 2.
and so is u, choose the APPARENT leading term of the denom.
(Even if the terms of this power cancel out. Example:
x/(x+sqrt(x^2+2x)) as x->-infinity, we should choose x.)
When a is NOT infinity:
4. If either denom is a trigpoly2 actually containing trig functions,
choose the leading term of the denom;
5. if num is a trigpoly2 etc, choose the leading term of the num.
It does NOT work on for example sqrt(1+x^2)/(4+x) as x->infinity,
as limsqrt1 will deal with such examples.
Return value is 0 for success, 1 for failure
*/
{ term num,denom,v,c,temp,deg,u,x,a,d;
int i,err;
unsigned short f,n;
assert(FUNCTOR(t) == LIMIT);
n = ARITY(t);
u = LIMITAND(t);
x = ARG(0,ARG(0,t));
a = ARG(1,ARG(0,t));
assert(FRACTION(u));
if(!ISINFINITE(a))
{ for(i=1;i>=0;i--) /* start with the denom */
{ num = ARG(i,u); /* when i==1 it is really the denominator */
denom = ARG(i ? 0: 1,u);
f = FUNCTOR(num);
v = ARG(0,num);
if(ONE(v))
continue;
if(!ATOMIC(num) && (f == SIN || f == TAN) && !ispolyin(denom,x))
// added last condition to stop it working on lim(x->2, sin(t^2-4)/(t-2))
{ err = limval(n==2 ? limit(ARG(0,t),v) : limit3(ARG(0,t),ARG(1,t),v),&d);
if(err || !ZERO(d) || NOTDEFINED(d))
continue;
if(FUNCTOR(v) == '*')
{ twoparts(v,x,&c,arg);
if(ONE(*arg))
continue;
}
else
*arg = v;
}
else if(trigpolyargs2(num,x)==2)
{ int savenvariables = get_nvariables();
unsigned short savenextassumption = get_nextassumption();
err = leading_term1(num,x,a,&c,°);
/* leading_term1 computes derivatives, and then
'check's that they are defined and nonzero, which
can introduce new variables and assumptions which
we are only using temporarily to choose *arg.
Get rid of them now.
*/
set_nvariables(savenvariables);
set_nextassumption(savenextassumption);
if(err || ZERO(deg) || equals(c, bounded_oscillations))
return 1;
*arg = product(c,make_power(sum(x,tnegate(a)),deg));
}
else
continue;
/* Now *arg has been computed by one of the clauses above,
but we still have to eliminate trivial values of *arg
that would not do any good */
if(ONE(*arg))
continue;
polyval(make_fraction(denom,*arg),&temp);
if(!contains(temp,FUNCTOR(x)))
return 1; /* arg differs from denom only by a
constant factor; don't divide by arg */
polyval(make_fraction(num,*arg),&temp);
if(!contains(temp,FUNCTOR(x)))
return 1; /* arg differs from num only by a
constant factor; don't divide by arg */
return 0;
}
return 1;
}
/* so now a is infinity or minusinfinity */
num = ARG(0,u);
denom = ARG(1,u);
if( ispolyin(num,x) && ispolyin(denom,x))
{ /* rational function, choose the highest power of x in denom */
makepoly(denom,x,&temp);
if(ARITY(temp) == 1)
return 1; /* constant denom */
/* don't use on c/x^n or c/x, that leads to a loop */
/* This loop is stopped by the next if-statement */
if( ( equals(denom,x) ||
(FUNCTOR(denom) == '^' && equals(ARG(0,denom),x))
)
&& !contains(num,FUNCTOR(x))
)
return 1;
*arg = make_power(x,make_int(ARITY(temp)-1));
return 0;
}
/* Now it's not a rational function. */
/* Example: u = (1+ \sqrt x)/(1-\sqrt x) */
/* Now check if num and denom are both 'ppolys' of some root or
power of x. See above for ppoly. If we don't restrict the
applicability of the code, though, it works on too-complicated
examples. For a long time it was restricted to the case
FUNCTOR(denom) == '+', but we need it to work on denominators
like x(x^3-1)^(1/3); then leadingterm is used on (x^3-1)^(1/3)
which is comprehensible. */
if(FUNCTOR(denom) != '+' && FUNCTOR(denom) != '*' && FUNCTOR(denom) != '^')
return 1;
err = ppoly(denom,x);
if(err)
return 1;
err = ppoly(num,x);
if(err)
return 1;
err = leading_term1(denom,x,a,&c,°);
if(err || equals(c,bounded_oscillations))
return 1;
if(FRACTION(deg) && ONE(ARG(0,deg)) && equals(ARG(1,deg),two) && contains(u,SQRT))
/* deg == 1/2 */
{ *arg = make_sqrt(x);
return 0;
}
if(FRACTION(deg) && ONE(ARG(0,deg)) && contains(u,ROOT))
/* deg == 1/2 */
{ *arg = make_root(ARG(1,deg),x);
return 0;
}
*arg = make_power(x,deg);
return 0;
}
/*_____________________________________________________________________*/
static int trig_approaches(unsigned short f, term c, approach ll, approach *ans)
/* f is COS, SIN, or ABSFUNCTOR. Compute the approach style
of f(x) to f(c) as x->c with the specified approach ll.
Return 0 for success, 1 for failure.
*/
{ int err;
term u;
unsigned short g;
double z;
long kk;
if(f == ABSFUNCTOR)
{ if(ZERO(c))
{ *ans = min;
return 0;
}
if(seminumerical(c))
{ deval(c,&z);
if(z == BADVAL)
return 1;
if(nearint(z,&kk) && kk==0)
{ *ans = min;
return 0;
}
if(z > 0.0)
{ *ans = ll;
return 0;
}
if(z < 0.0)
{ *ans = ll == min ? max : ll == max ? min : ll;
return 0;
}
}
polyval(c,&u);
if(ZERO(u))
{ *ans = min;
return 0;
}
err = infer(lessthan(zero,c));
if(!err)
{ *ans = ll;
return 0;
}
err = infer(lessthan(c,zero));
if(!err)
{ *ans = ll == min ? max : ll == max ? min : ll;
return 0;
}
return 1; /* can't determine sign of c */
}
/* Now f is SIN or COS */
/* sin is increasing exactly when cos is positive;
cos is increasing exactly when sin is negative;
So we compute or infer the sign of the other
function. */
g = (unsigned short) (f == SIN ? COS : SIN);
u = make_term(g,1);
ARGREP(u,0,c);
/* determine the sign of u */
if(seminumerical(u)) /* This will include things like sin(2n pi + pi/2) */
{ deval(u,&z);
if(z==BADVAL)
return 1;
if(nearint(z,&kk) && kk==0)
{ u = make_term(f,1);
ARGREP(u,0,c);
deval(u,&z);
assert(z != BADVAL && z != 0.0);
*ans = z < 0 ? min : max;
return 0;
}
if(z > 0)
{ *ans = f == SIN ? ll : ll==max ? min : ll==min ? max : ll;
return 0;
}
if(z < 0)
{ *ans = f == COS ? ll : ll==max ? min : ll==min ? max : ll;
return 0;
}
}
return 1; /* I don't think there's any hope of inferring the sign,
unless it has been assumed, and I don't think that
will happen in practice, so I'll give up a hypothetical
example for increased speed. */
}
/*_____________________________________________________________________*/
int contains_exp(term u, term x)
/* return 1 if u contains e^x or indeed e to any term
with x in it, unless the exponent is a reciprocal or negation of
a reciprocal. Return 0 otherwise. */
{ unsigned short i,n;
if(ATOMIC(u))
return 0;
if(FUNCTOR(u) == '^' && equals(ARG(0,u),eulere))
{ if(contains(ARG(1,u),FUNCTOR(x)) &&
!(FRACTION(ARG(1,u)) && ONE(ARG(0,ARG(1,u)))) &&
!(NEGATIVE(ARG(1,u)) && FRACTION(ARG(0,ARG(1,u))) && ONE(ARG(0,ARG(0,ARG(1,u)))))
)
return 1;
return 0;
}
n = ARITY(u);
for(i=0;i<n;i++)
{ if(contains_exp(ARG(i,u),x))
return 1;
}
return 0;
}
/*_______________________________________________________________________*/
static int unary_lim(unsigned short f, unsigned short dir, term x, term *ans, approach *l, approach *r)
/* x is a term; return *ans = f(x) if this is defined, and put
the approach styles of f to x in *l and *r if they can be deduced.
If f(x) is not defined, we want the value of lim(z->x,f(z)) if dir == 0 or lim(z->x,dir,f(z)),
(although dir is LEFTDIR or RIGHTDIR, not a term 'left' or 'right').
If they cannot be found, return 1 for failure. Return 0 for success.
f is a unary functor, but not LN, LOG, or a trig functor.
x may or may not be seminumerical; it may or may not lie in the domain
or closure of the domain of f; it may or may not be a singularity of f.
If x is a singularity of f, return *ans = infinity, minusinfinity, or
undefined, with appropriate values in *l and *r.
*/
{ /* First determine if x is a singularity of f or not */
*ans = make_term(f,1);
ARGREP(*ans,0,x);
switch(f)
{ case ATAN:
*l = max;
*r = min;
return 0;
case ASIN:
*l = max;
*r = min;
return 0;
case ACOS:
*l = min;
*r = max;
return 0;
case ASEC:
if(!infer(lessthan(x,minusone)) ||
!infer(lessthan(one,x))
)
{ *l = max;
*r = min;
return 0;
}
if(!infer(lessthan(minusone,x)) &&
!infer(lessthan(x,one))
)
{ *l = *r = dom_error;
return 2;
}
return 1;
case ACSC:
if(!infer(lessthan(x,minusone)) ||
!infer(lessthan(one,x))
)
{ *l = min;
*r = max;
return 0;
}
if(!infer(lessthan(minusone,x)) &&
!infer(lessthan(x,one))
)
{ *l = *r = dom_error;
return 2;
}
return 1;
case ACOT:
*l = min;
*r = max;
return 0;
case TANH:
*l = max;
*r = min;
return 0;
case SINH:
*l = max;
*r = min;
case COSH:
if(!infer(equation(x,zero)))
{ *l = min;
*r = min;
return 0;
}
if(!infer(lessthan(zero,x)))
{ *l = max;
*r = min;
return 0;
}
if(!infer(lessthan(x,zero)))
{ *l = min;
*r = max;
return 0;
}
return 1;
case COTH:
case CSCH:
*l = min;
*r = max;
if(!infer(equation(x,zero)))
*ans = dir == 0 ? undefined : dir == LEFTDIR ? minusinfinity : infinity;
return 0;
case SECH:
if(!infer(equation(x,zero)))
{ *l = max;
*r = max;
return 0;
}
if(!infer(lessthan(zero,x)))
{ *l = min;
*r = max;
return 0;
}
if(!infer(lessthan(x,zero)))
{ *l = max;
*r = min;
return 0;
}
return 1;
case ATANH:
if(!infer(lessthan(minusone,x)) &&
!infer(lessthan(x,one))
)
{ *l = max;
*r = min;
return 0;
}
if(!infer(le(x,minusone)) ||
!infer(le(one,x))
)
{ *l = *r = dom_error;
*ans = undefined;
return 2;
}
if(!infer(equation(x,minusone)))
{ *ans = minusinfinity;
*l = dom_error;
*r = min;
return 0;
}
if(!infer(equation(x,one)))
{ *ans = infinity;
*l = max;
*r = dom_error;
return 0;
}
return 1;
case ASINH:
*l = max;
*r = min;
return 0;
case ACOSH:
if(!infer(lessthan(one,x)))
{ *l = max;
*r = min;
return 0;
}
if(!infer(equation(x,one)))
{ *l = dom_error;
*r = min;
return 0;
}
if(!infer(lessthan(x,one)))
{ *l = *r = dom_error;
*ans = undefined;
return 2;
}
return 1;
case ACOTH:
if(!infer(lessthan(x,minusone)))
{ *l = min;
*r = max;
return 0;
}
if(!infer(lessthan(one,x)))
{ *l = min;
*r = max;
return 0;
}
if(!infer(equation(x,minusone)))
{ *l = min;
*r = dom_error;
*ans = minusinfinity;
return 0;
}
if(!infer(equation(x,one)))
{ *r = max;
*l = dom_error;
*ans = infinity;
return 0;
}
return 1;
case ACSCH:
*l = min;
*r = max;
if(!infer(nonzero(x)))
return 0;
if(!infer(equation(x,zero)))
{ *ans = dir == 0 ? undefined : dir == LEFTDIR ? minusinfinity : infinity;
return 0;
}
return 1;
case ASECH:
if(!infer(lessthan(zero,x)) &&
!infer(le(x,one))
)
{ *l = min;
*r = max;
return 0;
}
if(!infer(equation(x,zero)))
{ *l = dom_error;
*r = max;
*ans = infinity;
return 0;
}
if(!infer(equation(x,one)))
{ *ans = zero;
*r = dom_error;
*l = min;
return 0;
}
if(!infer(lessthan(x,zero)))
{ *ans = undefined;
*l = *r = dom_error;
return 2;
}
if(!infer(lessthan(one,x)))
{ *ans = undefined;
*l = *r = dom_error;
return 2;
}
}
return 1;
}
/*_______________________________________________________________________*/
static int simple_exponential_limit(term t, term *ans, approach *ll, approach *rr)
/* return 0 if limit t can be calculated using simple formulas for the
limit of c^x. Put the answer in *ans and the approach directions in *ll, *rr. */
{ term x,u,a,b,c,num,denom,power,q,powerlim,temp,p;
double z;
int err;
long kk;
approach l2,r2;
if(FUNCTOR(t)!= LIMIT)
return 1;
x = ARG(0,ARG(0,t));
a = ARG(1,ARG(0,t)); /* lim(x->a,u) */
u = LIMITAND(t);
if(FRACTION(u) && FUNCTOR(ARG(0,u)) == '^' && FUNCTOR(ARG(1,u)) == '^')
{ num = ARG(0,u);
denom = ARG(1,u);
b = ARG(0,num);
c = ARG(0,denom);
if(!seminumerical(b) || !seminumerical(c))
return 1;
if(equals(a,minusinfinity) && equals(ARG(1,num),x) && equals(ARG(1,denom),x))
{ /* lim(x->-infinity, (b/c)^x) =
lim(x->infinity, (c/b)^x */
q = b;
b = c;
b = q;
}
if(equals(a,infinity) && equals(ARG(1,num),x) && equals(ARG(1,denom),x))
{ /* then the answer is infinity, 1, or zero according
as b/c is > 1, = 1, or < 1
*/
deval(make_fraction(b,c),&z);
if(z == BADVAL)
return 1;
if(nearint(z,&kk) && kk == 1)
{ *ans = one;
*ll = *rr = min;
return 0;
}
if(z < 0.0)
{ *ans = undefined;
*ll = *rr = dom_error;
return 0;
}
if(z > 1.0)
{ *ans = infinity;
*ll = *rr = max;
return 0;
}
if(z < 1.0)
{ *ans = zero;
*ll = *rr = min;
return 0;
}
assert(0);
}
}
if(FUNCTOR(u) == '^')
{ c = ARG(0,u);
if(!seminumerical(c))
return 1;
power = ARG(1,u);
if(!contains(power,FUNCTOR(x)))
return 1;
/* Now, is c more or less than 1? */
deval(c,&z);
if(z == BADVAL)
return 1;
if(fabs(z-1) < VERYSMALL)
{ *ans = one;
*ll = *rr = min;
}
powerlim = ARITY(t) == 2 ? limit(ARG(0,t),power) : limit3(ARG(0,t),ARG(1,t),power);
err = limval_aux(1,powerlim,&q,&l2,&r2);
/* same as limval(powerlim,&q), but doesn't reset lhopital_depth */
if(err)
return 1;
if(equals(q,infinity))
{ if(z < 1.0)
{ *ans = zero;
*ll = *rr = min;
}
else
{ *ans = infinity;
*ll = *rr = max;
}
return 0;
}
if(equals(q,minusinfinity))
{ if(z < 1.0)
{ *ans = infinity;
*ll = *rr = max;
}
else
{ *ans = zero;
*ll = *rr = min;
}
return 0;
}
if(NOTDEFINED(q))
{ *ans = q;
return 0;
}
polyval(make_power(c,q),ans);
return 0;
}
if(FUNCTOR(u) == '*' && equals(a,infinity) && ARITY(u) == 2) /* example, x e^(-x^2) */
{ p = ARG(0,u);
q = ARG(1,u);
if(FUNCTOR(q) == '^' && !contains(ARG(0,q),FUNCTOR(x)) && ispolyin(p,x))
{ err = limval(limit(ARG(0,t),ARG(1,q)),&temp);
if(!err)
{ if(equals(temp,minusinfinity))
{ *ans = zero;
return 0;
}
}
}
}
return 1;
}
/*________________________________________________________________*/
static int oscillatory(term t, term w)
/* Return 1 if w(x) has bounded oscillations as x->a, where
t is some limit as x->a. The limitand of t is not used.
Return 0 otherwise, indicating that the limit of w exists
and is finite, or that w is not a sum, product, sin or cos, or that
the limit of w cannot be calculated, or is infinite or undefined.
Specifically return 1 for oscillatory
cos and sin terms, products containing such terms, and
sums containing oscillatory terms whose other summands
are bounded as x->a.
*/
{ term temp,mid;
int err, flag;
approach ll,rr;
unsigned short i,n;
term x = ARG(0,ARG(0,t));
term a = ARG(1,ARG(0,t));
term p;
if(NEGATIVE(w))
return oscillatory(t,ARG(0,w));
if(FUNCTOR(w) == '+')
{ n = ARITY(w);
flag = 0;
for(i=0;i<n;i++)
{ if(oscillatory(t,ARG(i,w)))
flag = 1;
else if(!finitelimit(t,ARG(i,w)))
return 0;
}
return flag;
}
if(FUNCTOR(w) == '^')
{ if(obviously_positive(ARG(1,w)))
return oscillatory(t,ARG(0,w));
return 0;
}
if(FUNCTOR(w)==SIN || FUNCTOR(w)==COS)
{ if(ISINFINITE(a) && equals(ARG(0,w),x))
return 1; /* without further ado */
if(ISINFINITE(a) && FUNCTOR(ARG(0,w))=='^' &&
INTEGERP(ARG(1,ARG(0,w))) && equals(ARG(0,ARG(0,w)),x)
)
return 1; /* cos(x^n) is oscillatory at infinity */
temp = ARG(0,w);
/* now check temp for whether it contributes oscillations. Does
the limit of sin(temp) have bounded oscillations? */
mid = ARITY(t)==2 ? limit(ARG(0,t),sin1(temp)) : limit3(ARG(0,t),ARG(1,t),sin1(temp));
err = limval_aux(1,mid,&p,&ll,&rr);
if(err)
return 0;
if(equals(p,bounded_oscillations))
return 1;
return 0;
}
if(FUNCTOR(w) == '*')
{ n = ARITY(w);
flag = 0;
for(i=0;i<n;i++)
{ if(oscillatory(t,ARG(i,w)))
flag = 1;
else if(!finitelimit(t,ARG(i,w)))
return 0;
}
}
return 0;
}
/*__________________________________________________________________*/
static int finitelimit(term t, term u)
/* t is a limit term. Return 1 if lim(ARG(0,t),u) exists and is
finite (for a two-sided limit), or if lim(ARG(0,t),ARG(1,t),u)
exists and is finite if t is a one-sided limit. Return 0 if
the limit can't be calculated or is not finite.
*/
{ term x = ARG(0,ARG(0,t));
term a = ARG(1,ARG(0,t)); /* lim(x->a,u) is being considered */
term v,val;
int err;
if(!depends(u,x))
return 1;
if(equals(a,infinity))
{ if(equals(u,x))
return 0;
if(FUNCTOR(u) == '^' && obviously_positive(ARG(1,u)) &&
equals(ARG(0,u),x)
)
return 0;
}
if(ARITY(t) == 2)
v = limit(ARG(0,t),u);
else
v = limit3(ARG(0,t),ARG(1,t),u);
err = limval(v,&val);
if(err)
return 0;
if(!NOTDEFINED(val))
return 1;
return 0;
}
/*____________________________________________________________________________________________*/
static int logarithmic(term mid, term h)
/* return 1 if mid is a logarithm of an algebraic function of h, or a constant multiple thereof */
{ term c,s;
unsigned short f;
if(NEGATIVE(mid))
mid = ARG(0,mid);
f = FUNCTOR(mid);
if(f == '/' || f == '*')
{ twoparts(mid,h,&c,&s);
mid = s;
}
if((f == LN || f == LOG) && algebraic_in2(ARG(0,mid),h))
return 1;
if(f == LOGB && algebraic_in2(ARG(1,mid),h))
return 1;
return 0;
}
/*_______________________________________________________________________*/
static int loglim(int topcall, term t, approach *l, approach *r, term *ans)
/* t is a limit term, whose limitand is a fraction, or a
product of arity 2, one of whose args is a ln or power of a ln.
Compute the limit, using the fact that algebraic limits dominate logarithmic
limits. Return the answer in *ans, returning zero for success, 1 for
failure; in case of failure, *ans is garbage. Inputs topcall, l, r are as
for limval_aux. If topcall is zero we must compute l and r.
*/
{ term u,v,w,prod,a,h,power,uval,wval,p,q,s,temp,c,deg;
int sign, powersign,wsign,err;
approach ll, rr, ll2, rr2;
if(FUNCTOR(t) != LIMIT)
return 1;
prod = LIMITAND(t);
a = ARG(1,ARG(0,t)); /* lim(x->a,prod) */
if(FRACTION(prod))
{ u = ARG(0,prod);
if(FUNCTOR(ARG(1,prod)) == '^')
v = make_power(ARG(0,ARG(1,prod)),tnegate(ARG(1,ARG(1,prod))));
else
v = make_power(ARG(1,prod),minusone);
}
else if(FUNCTOR(prod) == '*' && ARITY(prod) == 2)
{ u = ARG(0,prod);
v = ARG(1,prod);
}
else
return 1; /* wrong input */
if(contains(u,LN) && !contains(v,LN))
{ temp = u; /* swap u and v */
u = v;
v = temp; /* so now v is the log term */
}
h = ARG(0,ARG(0,t)); /* the limit variable */
if(!algebraic_in2(u,h))
return 1;
if(FUNCTOR(v) == '^')
{ power = ARG(1,v);
if(contains(power,FUNCTOR(h)))
return 1;
if(FUNCTOR(ARG(0,v)) != LN)
return 1;
powersign = get_sign(power);
w = ARG(0,ARG(0,v)); /* arg of the ln term */
}
else if(FUNCTOR(v) == LN)
w = ARG(0,v);
else
return 1; // w has to be a LN or power of LN
if(!algebraic_in2(w,h))
return 1;
if((ZERO(a) || equals(a,infinity)) &&
equals(w,h) &&
(equals(u,h) ||
(FUNCTOR(u) == '^' && equals(ARG(0,u),h) &&
obviously_positive(ARG(1,u))
) ||
(FUNCTOR(u) == SQRT && equals(ARG(0,u),h)) ||
(FUNCTOR(u) == ROOT && equals(ARG(1,u),h))
)
)
{ if(ZERO(a))
{ if(ARITY(t) == 2 || equals(ARG(2,t),left))
{ *ans = undefined;
return 0;
}
*ans = zero;
*r = max; // corrected 6.8.13
*l = dom_error;
return 0;
}
/* now a is infinity */
*ans = infinity;
*l = *r = max;
return 0;
}
if(equals(w,h) &&
(ZERO(a) || equals(a,infinity)) &&
(FUNCTOR(u) == '^' && equals(ARG(0,u),h) &&
obviously_negative(ARG(1,u))
)
)
{ if(ZERO(a))
{ if(ARITY(t) == 3 && equals(ARG(2,t),left))
{ *ans = infinity;
*r = max;
*l = dom_error;
return 0;
}
*ans = undefined;
return 0;
}
*ans = zero;
*l = *r = min;
return 0;
}
q = ARITY(t) == 3 ? limit3(ARG(0,t),ARG(1,t),u) : limit(ARG(0,t),u);
err = limval_aux(topcall,q,&uval,&ll,&rr);
if(err)
return 1;
q = ARITY(t) == 3 ? limit3(ARG(0,t),ARG(1,t),w) : limit(ARG(0,t),w);
err = limval_aux(topcall,q,&wval,&ll2,&rr2);
if(err)
return 1;
/* now what's the value of uval ln(wval)? */
if(equals(wval,undefined) ||
equals(uval,undefined) ||
equals(wval,minusinfinity)
)
{ *ans = undefined;
return 0;
}
/* oscillatory approaches are impossible for algebraic functions */
if(ONE(wval))
{ /* e.g. lim(x->infinity, x ln(1- 1/x^n) */
if(FUNCTOR(v) == LN)
{ q = sum(w,minusone);
err = leading_term(q,h,a,&c,°);
if(err || ZERO(deg))
return 1;
else
s = product(u,product(c,make_power(h,deg)));
p = ARITY(t) == 3 ? limit3(ARG(0,t),ARG(1,t),s) : limit(ARG(0,t),s);
err = limval_aux(topcall,p,ans,l,r);
*ans = zero;
return err;
}
if(FUNCTOR(v) == '^' && FUNCTOR(ARG(0,v)) == LN)
{ q = sum(w,minusone);
err = leading_term(q,h,a,&c,°);
if(err || ZERO(deg))
return 1;
deg = product(ARG(1,v),deg);
if(ZERO(deg))
return 1;
s = product(u,product(c,make_power(h,deg)));
p = ARITY(t) == 3 ? limit3(ARG(0,t),ARG(1,t),s) : limit(ARG(0,t),s);
err = limval_aux(topcall,p,ans,l,r);
*ans = zero;
return err;
}
return 1;
}
if(!ZERO(wval) && !equals(wval,infinity))
{ err = infer(ne(wval,one));
if(err)
return 1; /* give up */
}
if(equals(uval,zero))
/* an algebraic zero kills a logarithmic singularity */
{ *ans = zero;
if(!topcall)
{ *l = approach_product(ll,ll2,LEFTDIR);
*r = approach_product(rr,rr2,RIGHTDIR);
}
return 0;
}
/* Now, is wval more or less than one? */
if(equals(wval,infinity))
wsign = 1;
else if(ZERO(wval))
wsign = -1;
else
{ polyval(sum(wval,minusone),&temp);
wsign = get_sign(temp);
if(wsign == 0)
return 1; /* assert(0) */
}
if(ISINFINITE(uval))
{ *ans = wsign > 0 ? uval : tnegate(uval);
if(equals(uval,infinity))
*l = *r = max;
else
*l = *r = min;
return 0;
}
sign = get_sign(uval);
if(sign == 0)
{ *ans = zero;
if(!topcall)
{ *l = approach_product(ll,ll2,LEFTDIR);
*r = approach_product(rr,rr2,RIGHTDIR);
}
return 0;
}
/* Now, uval is neither infinite nor zero */
if(equals(wval,infinity))
{ *ans = sign > 0 ? infinity : minusinfinity;
if(equals(*ans,infinity))
*l = *r = max;
else
*l = *r = min;
return 0;
}
if(ZERO(wval))
{ *ans = sign > 0 ? minusinfinity: infinity;
if(equals(*ans,infinity))
*l = *r = max;
else
*l = *r = min;
return 0;
}
/* Now both limits are finite, and wval is not 1 */
if(FUNCTOR(v) == LN)
{ polyval(product(uval, ln1(wval)), ans);
if(!topcall)
{ *l = approach_product(ll,ll2,LEFTDIR);
*r = approach_product(rr,rr2,RIGHTDIR);
}
return 0;
}
if(FUNCTOR(v) == '^' && FUNCTOR(ARG(0,v)) == LN)
{ polyval(product(uval,make_power(ln1(wval),ARG(1,v))),ans);
if(!topcall)
{ powersign = get_sign(ARG(1,v));
if(powersign == 0)
{ *r = rr;
*l = ll;
return 0;
}
if(powersign < 0)
{ ll2 = ll2 == max ? min : max;
rr2 = rr2 == max ? min : max;
}
*l = approach_product(ll,ll2,LEFTDIR);
*r = approach_product(rr,rr2,RIGHTDIR);
return 0;
}
return 0;
}
return 1;
}
/*_____________________________________________________________________________*/
static int twovarexps(term p, term x)
/* return 1 if p contains a sum containing two different terms with variable exponents */
{ unsigned short n = ARITY(p);
term v,c,s,test;
int flag = 0;
int i;
if(ATOMIC(p))
return 0;
if(FUNCTOR(p) != '+')
{ for(i=0;i<n;i++)
{ if(twovarexps(ARG(i,p),x))
return 1;
}
return 0;
}
for(i=0;i<n;i++)
{ v = ARG(i,p);
if(NEGATIVE(v))
v = ARG(0,v);
if(FRACTION(v))
{ if(!contains(ARG(1,v),FUNCTOR(x)))
v = ARG(0,v);
else if(!contains(ARG(0,v),FUNCTOR(x)))
v = ARG(1,v);
}
if(FUNCTOR(v) == '*')
{ twoparts(v,x,&c,&s);
v = s;
}
if(FUNCTOR(v) == '^' && contains(ARG(1,v),FUNCTOR(x)))
{ if(!flag)
{ test = ARG(0,v);
flag = 1;
}
else
{ if(!equals(ARG(0,v),test))
return 1; /* varexp with different base. */
}
}
}
return 0;
}
/*________________________________________________________________________________________*/
static int badlimit(term t)
/* t is a limit term. Return 0 if we are sure we can't do this limit.
Return 1 otherwise.
*/
{ term x,u,a,p,q;
unsigned short f;
u = LIMITAND(t);
x = ARG(0,ARG(0,t));
a = ARG(1,ARG(0,t));
f = FUNCTOR(u);
if(f == '/' && equals(a,infinity) &&
twovarexps(ARG(0,u),x) &&
twovarexps(ARG(1,u),x)
)
return 0; /* e.g. the limit arising from the ratio test on sum( a^n + b^n,n,1,infinity) */
if(f == '^')
{ /* lim(x->infinity,(a^x + b^x)^(1/x)) is impossible. And worse,
it leads limval into infinite regress via L'Hopital's rule.
This arises if you try to apply the root test to an infinite
series which is sum of two geometric series. */
p = ARG(0,u);
q = ARG(1,u);
if(FRACTION(q) && equals(ARG(1,q),x) &&
equals(a,infinity) &&
!contains(ARG(0,q),FUNCTOR(x)) &&
FUNCTOR(p) == '+' &&
twovarexps(p,x)
)
return 0;
}
return 1;
}
Sindbad File Manager Version 1.0, Coded By Sindbad EG ~ The Terrorists