static ex exp_evalf(const ex & x)
{
- BEGIN_TYPECHECK
- TYPECHECK(x,numeric)
- END_TYPECHECK(exp(x))
+ if (is_exactly_a<numeric>(x))
+ return exp(ex_to<numeric>(x));
- return exp(ex_to<numeric>(x)); // -> numeric exp(numeric)
+ return exp(x).hold();
}
static ex exp_eval(const ex & x)
// exp(float)
if (x.info(info_flags::numeric) && !x.info(info_flags::crational))
- return exp_evalf(x);
+ return exp(ex_to<numeric>(x));
return exp(x).hold();
}
static ex log_evalf(const ex & x)
{
- BEGIN_TYPECHECK
- TYPECHECK(x,numeric)
- END_TYPECHECK(log(x))
+ if (is_exactly_a<numeric>(x))
+ return log(ex_to<numeric>(x));
- return log(ex_to<numeric>(x)); // -> numeric log(numeric)
+ return log(x).hold();
}
static ex log_eval(const ex & x)
return (Pi*I*_num_1_2());
// log(float)
if (!x.info(info_flags::crational))
- return log_evalf(x);
+ return log(ex_to<numeric>(x));
}
// log(exp(t)) -> t (if -Pi < t.imag() <= Pi):
if (is_ex_the_function(x, exp)) {
int order,
unsigned options)
{
- GINAC_ASSERT(is_ex_exactly_of_type(rel.lhs(),symbol));
+ GINAC_ASSERT(is_exactly_a<symbol>(rel.lhs()));
ex arg_pt;
bool must_expand_arg = false;
// maybe substitution of rel into arg fails because of a pole
// This is the branch point: Series expand the argument first, then
// trivially factorize it to isolate that part which has constant
// leading coefficient in this fashion:
- // x^n + Order(x^(n+m)) -> x^n * (1 + Order(x^m)).
+ // x^n + x^(n+1) +...+ Order(x^(n+m)) -> x^n * (1 + x +...+ Order(x^m)).
// Return a plain n*log(x) for the x^n part and series expand the
// other part. Add them together and reexpand again in order to have
// one unnested pseries object. All this also works for negative n.
- const pseries argser = ex_to<pseries>(arg.series(rel, order, options));
- const symbol *s = static_cast<symbol *>(rel.lhs().bp);
+ pseries argser; // series expansion of log's argument
+ unsigned extra_ord = 0; // extra expansion order
+ do {
+ // oops, the argument expanded to a pure Order(x^something)...
+ argser = ex_to<pseries>(arg.series(rel, order+extra_ord, options));
+ ++extra_ord;
+ } while (!argser.is_terminating() && argser.nops()==1);
+
+ const symbol &s = ex_to<symbol>(rel.lhs());
const ex point = rel.rhs();
- const int n = argser.ldegree(*s);
+ const int n = argser.ldegree(s);
epvector seq;
// construct what we carelessly called the n*log(x) term above
- ex coeff = argser.coeff(*s, n);
+ const ex coeff = argser.coeff(s, n);
// expand the log, but only if coeff is real and > 0, since otherwise
// it would make the branch cut run into the wrong direction
if (coeff.info(info_flags::positive))
- seq.push_back(expair(n*log(*s-point)+log(coeff), _ex0()));
+ seq.push_back(expair(n*log(s-point)+log(coeff), _ex0()));
else
- seq.push_back(expair(log(coeff*pow(*s-point, n)), _ex0()));
+ seq.push_back(expair(log(coeff*pow(s-point, n)), _ex0()));
+
if (!argser.is_terminating() || argser.nops()!=1) {
- // in this case n more terms are needed
+ // in this case n more (or less) terms are needed
// (sadly, to generate them, we have to start from the beginning)
- ex newarg = ex_to<pseries>((arg/coeff).series(rel, order+n, options)).shift_exponents(-n).convert_to_poly(true);
+ const ex newarg = ex_to<pseries>((arg/coeff).series(rel, order+n, options)).shift_exponents(-n).convert_to_poly(true);
return pseries(rel, seq).add_series(ex_to<pseries>(log(newarg).series(rel, order, options)));
} else // it was a monomial
return pseries(rel, seq);
// method:
// This is the branch cut: assemble the primitive series manually and
// then add the corresponding complex step function.
- const symbol *s = static_cast<symbol *>(rel.lhs().bp);
+ const symbol &s = ex_to<symbol>(rel.lhs());
const ex point = rel.rhs();
const symbol foo;
- const ex replarg = series(log(arg), *s==foo, order).subs(foo==point);
+ const ex replarg = series(log(arg), s==foo, order).subs(foo==point);
epvector seq;
seq.push_back(expair(-I*csgn(arg*I)*Pi, _ex0()));
seq.push_back(expair(Order(_ex1()), order));
static ex sin_evalf(const ex & x)
{
- BEGIN_TYPECHECK
- TYPECHECK(x,numeric)
- END_TYPECHECK(sin(x))
+ if (is_exactly_a<numeric>(x))
+ return sin(ex_to<numeric>(x));
- return sin(ex_to<numeric>(x)); // -> numeric sin(numeric)
+ return sin(x).hold();
}
static ex sin_eval(const ex & x)
// sin(float) -> float
if (x.info(info_flags::numeric) && !x.info(info_flags::crational))
- return sin_evalf(x);
+ return sin(ex_to<numeric>(x));
return sin(x).hold();
}
static ex cos_evalf(const ex & x)
{
- BEGIN_TYPECHECK
- TYPECHECK(x,numeric)
- END_TYPECHECK(cos(x))
+ if (is_exactly_a<numeric>(x))
+ return cos(ex_to<numeric>(x));
- return cos(ex_to<numeric>(x)); // -> numeric cos(numeric)
+ return cos(x).hold();
}
static ex cos_eval(const ex & x)
// cos(float) -> float
if (x.info(info_flags::numeric) && !x.info(info_flags::crational))
- return cos_evalf(x);
+ return cos(ex_to<numeric>(x));
return cos(x).hold();
}
static ex tan_evalf(const ex & x)
{
- BEGIN_TYPECHECK
- TYPECHECK(x,numeric)
- END_TYPECHECK(tan(x)) // -> numeric tan(numeric)
+ if (is_exactly_a<numeric>(x))
+ return tan(ex_to<numeric>(x));
- return tan(ex_to<numeric>(x));
+ return tan(x).hold();
}
static ex tan_eval(const ex & x)
// tan(float) -> float
if (x.info(info_flags::numeric) && !x.info(info_flags::crational)) {
- return tan_evalf(x);
+ return tan(ex_to<numeric>(x));
}
return tan(x).hold();
int order,
unsigned options)
{
- GINAC_ASSERT(is_ex_exactly_of_type(rel.lhs(),symbol));
+ GINAC_ASSERT(is_exactly_a<symbol>(rel.lhs()));
// method:
// Taylor series where there is no pole falls back to tan_deriv.
// On a pole simply expand sin(x)/cos(x).
static ex asin_evalf(const ex & x)
{
- BEGIN_TYPECHECK
- TYPECHECK(x,numeric)
- END_TYPECHECK(asin(x))
+ if (is_exactly_a<numeric>(x))
+ return asin(ex_to<numeric>(x));
- return asin(ex_to<numeric>(x)); // -> numeric asin(numeric)
+ return asin(x).hold();
}
static ex asin_eval(const ex & x)
return _num_1_2()*Pi;
// asin(float) -> float
if (!x.info(info_flags::crational))
- return asin_evalf(x);
+ return asin(ex_to<numeric>(x));
}
return asin(x).hold();
static ex acos_evalf(const ex & x)
{
- BEGIN_TYPECHECK
- TYPECHECK(x,numeric)
- END_TYPECHECK(acos(x))
+ if (is_exactly_a<numeric>(x))
+ return acos(ex_to<numeric>(x));
- return acos(ex_to<numeric>(x)); // -> numeric acos(numeric)
+ return acos(x).hold();
}
static ex acos_eval(const ex & x)
return Pi;
// acos(float) -> float
if (!x.info(info_flags::crational))
- return acos_evalf(x);
+ return acos(ex_to<numeric>(x));
}
return acos(x).hold();
static ex atan_evalf(const ex & x)
{
- BEGIN_TYPECHECK
- TYPECHECK(x,numeric)
- END_TYPECHECK(atan(x))
+ if (is_exactly_a<numeric>(x))
+ return atan(ex_to<numeric>(x));
- return atan(ex_to<numeric>(x)); // -> numeric atan(numeric)
+ return atan(x).hold();
}
static ex atan_eval(const ex & x)
throw (pole_error("atan_eval(): logarithmic pole",0));
// atan(float) -> float
if (!x.info(info_flags::crational))
- return atan_evalf(x);
+ return atan(ex_to<numeric>(x));
}
return atan(x).hold();
int order,
unsigned options)
{
- GINAC_ASSERT(is_ex_exactly_of_type(rel.lhs(),symbol));
+ GINAC_ASSERT(is_exactly_a<symbol>(rel.lhs()));
// method:
// Taylor series where there is no pole or cut falls back to atan_deriv.
// There are two branch cuts, one runnig from I up the imaginary axis and
// method:
// This is the branch cut: assemble the primitive series manually and
// then add the corresponding complex step function.
- const symbol *s = static_cast<symbol *>(rel.lhs().bp);
+ const symbol &s = ex_to<symbol>(rel.lhs());
const ex point = rel.rhs();
const symbol foo;
- const ex replarg = series(atan(arg), *s==foo, order).subs(foo==point);
+ const ex replarg = series(atan(arg), s==foo, order).subs(foo==point);
ex Order0correction = replarg.op(0)+csgn(arg)*Pi*_ex_1_2();
if ((I*arg_pt)<_ex0())
Order0correction += log((I*arg_pt+_ex_1())/(I*arg_pt+_ex1()))*I*_ex_1_2();
// inverse tangent (atan2(y,x))
//////////
-static ex atan2_evalf(const ex & y, const ex & x)
+static ex atan2_evalf(const ex &y, const ex &x)
{
- BEGIN_TYPECHECK
- TYPECHECK(y,numeric)
- TYPECHECK(x,numeric)
- END_TYPECHECK(atan2(y,x))
+ if (is_exactly_a<numeric>(y) && is_exactly_a<numeric>(x))
+ return atan2(ex_to<numeric>(y), ex_to<numeric>(x));
- return atan(ex_to<numeric>(y),ex_to<numeric>(x)); // -> numeric atan(numeric)
+ return atan2(y, x).hold();
}
static ex atan2_eval(const ex & y, const ex & x)
static ex sinh_evalf(const ex & x)
{
- BEGIN_TYPECHECK
- TYPECHECK(x,numeric)
- END_TYPECHECK(sinh(x))
+ if (is_exactly_a<numeric>(x))
+ return sinh(ex_to<numeric>(x));
- return sinh(ex_to<numeric>(x)); // -> numeric sinh(numeric)
+ return sinh(x).hold();
}
static ex sinh_eval(const ex & x)
if (x.is_zero()) // sinh(0) -> 0
return _ex0();
if (!x.info(info_flags::crational)) // sinh(float) -> float
- return sinh_evalf(x);
+ return sinh(ex_to<numeric>(x));
}
if ((x/Pi).info(info_flags::numeric) &&
static ex cosh_evalf(const ex & x)
{
- BEGIN_TYPECHECK
- TYPECHECK(x,numeric)
- END_TYPECHECK(cosh(x))
+ if (is_exactly_a<numeric>(x))
+ return cosh(ex_to<numeric>(x));
- return cosh(ex_to<numeric>(x)); // -> numeric cosh(numeric)
+ return cosh(x).hold();
}
static ex cosh_eval(const ex & x)
if (x.is_zero()) // cosh(0) -> 1
return _ex1();
if (!x.info(info_flags::crational)) // cosh(float) -> float
- return cosh_evalf(x);
+ return cosh(ex_to<numeric>(x));
}
if ((x/Pi).info(info_flags::numeric) &&
static ex tanh_evalf(const ex & x)
{
- BEGIN_TYPECHECK
- TYPECHECK(x,numeric)
- END_TYPECHECK(tanh(x))
+ if (is_exactly_a<numeric>(x))
+ return tanh(ex_to<numeric>(x));
- return tanh(ex_to<numeric>(x)); // -> numeric tanh(numeric)
+ return tanh(x).hold();
}
static ex tanh_eval(const ex & x)
if (x.is_zero()) // tanh(0) -> 0
return _ex0();
if (!x.info(info_flags::crational)) // tanh(float) -> float
- return tanh_evalf(x);
+ return tanh(ex_to<numeric>(x));
}
if ((x/Pi).info(info_flags::numeric) &&
int order,
unsigned options)
{
- GINAC_ASSERT(is_ex_exactly_of_type(rel.lhs(),symbol));
+ GINAC_ASSERT(is_exactly_a<symbol>(rel.lhs()));
// method:
// Taylor series where there is no pole falls back to tanh_deriv.
// On a pole simply expand sinh(x)/cosh(x).
static ex asinh_evalf(const ex & x)
{
- BEGIN_TYPECHECK
- TYPECHECK(x,numeric)
- END_TYPECHECK(asinh(x))
+ if (is_exactly_a<numeric>(x))
+ return asinh(ex_to<numeric>(x));
- return asinh(ex_to<numeric>(x)); // -> numeric asinh(numeric)
+ return asinh(x).hold();
}
static ex asinh_eval(const ex & x)
return _ex0();
// asinh(float) -> float
if (!x.info(info_flags::crational))
- return asinh_evalf(x);
+ return asinh(ex_to<numeric>(x));
}
return asinh(x).hold();
static ex acosh_evalf(const ex & x)
{
- BEGIN_TYPECHECK
- TYPECHECK(x,numeric)
- END_TYPECHECK(acosh(x))
+ if (is_exactly_a<numeric>(x))
+ return acosh(ex_to<numeric>(x));
- return acosh(ex_to<numeric>(x)); // -> numeric acosh(numeric)
+ return acosh(x).hold();
}
static ex acosh_eval(const ex & x)
return Pi*I;
// acosh(float) -> float
if (!x.info(info_flags::crational))
- return acosh_evalf(x);
+ return acosh(ex_to<numeric>(x));
}
return acosh(x).hold();
static ex atanh_evalf(const ex & x)
{
- BEGIN_TYPECHECK
- TYPECHECK(x,numeric)
- END_TYPECHECK(atanh(x))
+ if (is_exactly_a<numeric>(x))
+ return atanh(ex_to<numeric>(x));
- return atanh(ex_to<numeric>(x)); // -> numeric atanh(numeric)
+ return atanh(x).hold();
}
static ex atanh_eval(const ex & x)
throw (pole_error("atanh_eval(): logarithmic pole",0));
// atanh(float) -> float
if (!x.info(info_flags::crational))
- return atanh_evalf(x);
+ return atanh(ex_to<numeric>(x));
}
return atanh(x).hold();
int order,
unsigned options)
{
- GINAC_ASSERT(is_ex_exactly_of_type(rel.lhs(),symbol));
+ GINAC_ASSERT(is_exactly_a<symbol>(rel.lhs()));
// method:
// Taylor series where there is no pole or cut falls back to atanh_deriv.
// There are two branch cuts, one runnig from 1 up the real axis and one
// method:
// This is the branch cut: assemble the primitive series manually and
// then add the corresponding complex step function.
- const symbol *s = static_cast<symbol *>(rel.lhs().bp);
+ const symbol &s = ex_to<symbol>(rel.lhs());
const ex point = rel.rhs();
const symbol foo;
- const ex replarg = series(atanh(arg), *s==foo, order).subs(foo==point);
+ const ex replarg = series(atanh(arg), s==foo, order).subs(foo==point);
ex Order0correction = replarg.op(0)+csgn(I*arg)*Pi*I*_ex1_2();
if (arg_pt<_ex0())
Order0correction += log((arg_pt+_ex_1())/(arg_pt+_ex1()))*_ex1_2();