-ex tan_evalf(ex const & x)
-{
- BEGIN_TYPECHECK
- TYPECHECK(x,numeric)
- END_TYPECHECK(tan(x)) // -> numeric tan(numeric)
-
- return tan(ex_to_numeric(x));
-}
-
-ex tan_eval(ex const & x)
-{
- // tan(n*Pi/3) -> {0|3^(1/2)|-(3^(1/2))}
- ex ThreeExOverPi=numTHREE()*x/Pi;
- if (ThreeExOverPi.info(info_flags::integer)) {
- numeric z=mod(ex_to_numeric(ThreeExOverPi),numeric(3));
- if (z.is_equal(numZERO()))
- return exZERO();
- if (z.is_equal(numONE()))
- return power(exTHREE(),exHALF());
- if (z.is_equal(numTWO()))
- return -power(exTHREE(),exHALF());
- }
-
- // tan((2n+1)*Pi/2) -> throw
- ex ExOverPiMinusHalf=x/Pi-exHALF();
- if (ExOverPiMinusHalf.info(info_flags::integer))
- throw (std::domain_error("tan_eval(): infinity"));
-
- if (is_ex_exactly_of_type(x, function)) {
- ex t=x.op(0);
- // tan(atan(x)) -> x
- if (is_ex_the_function(x, atan))
- return t;
- // tan(asin(x)) -> x*(1+x^2)^(-1/2)
- if (is_ex_the_function(x, asin))
- return t*power(exONE()-power(t,exTWO()),exMINUSHALF());
- // tan(acos(x)) -> (1-x^2)^(1/2)/x
- if (is_ex_the_function(x, acos))
- return power(t,exMINUSONE())*power(exONE()-power(t,exTWO()),exHALF());
- }
-
- // tan(float) -> float
- if (x.info(info_flags::numeric) && !x.info(info_flags::rational)) {
- return tan_evalf(x);
- }
-
- return tan(x).hold();
-}
-
-ex tan_diff(ex const & x, unsigned diff_param)
-{
- ASSERT(diff_param==0);
-
- return (1+power(tan(x),exTWO()));
-}
-
-REGISTER_FUNCTION(tan, tan_eval, tan_evalf, tan_diff, NULL);
+static ex tan_evalf(const ex & x)
+{
+ BEGIN_TYPECHECK
+ TYPECHECK(x,numeric)
+ END_TYPECHECK(tan(x)) // -> numeric tan(numeric)
+
+ return tan(ex_to_numeric(x));
+}
+
+static ex tan_eval(const ex & x)
+{
+ // tan(n/d*Pi) -> { all known non-nested radicals }
+ ex SixtyExOverPi = _ex60()*x/Pi;
+ ex sign = _ex1();
+ if (SixtyExOverPi.info(info_flags::integer)) {
+ numeric z = mod(ex_to_numeric(SixtyExOverPi),_num60());
+ if (z>=_num60()) {
+ // wrap to interval [0, Pi)
+ z -= _num60();
+ }
+ if (z>=_num30()) {
+ // wrap to interval [0, Pi/2)
+ z = _num60()-z;
+ sign = _ex_1();
+ }
+ if (z.is_equal(_num0())) // tan(0) -> 0
+ return _ex0();
+ if (z.is_equal(_num5())) // tan(Pi/12) -> 2-sqrt(3)
+ return sign*(_ex2()-power(_ex3(),_ex1_2()));
+ if (z.is_equal(_num10())) // tan(Pi/6) -> sqrt(3)/3
+ return sign*_ex1_3()*power(_ex3(),_ex1_2());
+ if (z.is_equal(_num15())) // tan(Pi/4) -> 1
+ return sign*_ex1();
+ if (z.is_equal(_num20())) // tan(Pi/3) -> sqrt(3)
+ return sign*power(_ex3(),_ex1_2());
+ if (z.is_equal(_num25())) // tan(5/12*Pi) -> 2+sqrt(3)
+ return sign*(power(_ex3(),_ex1_2())+_ex2());
+ if (z.is_equal(_num30())) // tan(Pi/2) -> infinity
+ throw (pole_error("tan_eval(): simple pole",1));
+ }
+
+ if (is_ex_exactly_of_type(x, function)) {
+ ex t = x.op(0);
+ // tan(atan(x)) -> x
+ if (is_ex_the_function(x, atan))
+ return t;
+ // tan(asin(x)) -> x*(1+x^2)^(-1/2)
+ if (is_ex_the_function(x, asin))
+ return t*power(_ex1()-power(t,_ex2()),_ex_1_2());
+ // tan(acos(x)) -> (1-x^2)^(1/2)/x
+ if (is_ex_the_function(x, acos))
+ return power(t,_ex_1())*power(_ex1()-power(t,_ex2()),_ex1_2());
+ }
+
+ // tan(float) -> float
+ if (x.info(info_flags::numeric) && !x.info(info_flags::crational)) {
+ return tan_evalf(x);
+ }
+
+ return tan(x).hold();
+}
+
+static ex tan_deriv(const ex & x, unsigned deriv_param)
+{
+ GINAC_ASSERT(deriv_param==0);
+
+ // d/dx tan(x) -> 1+tan(x)^2;
+ return (_ex1()+power(tan(x),_ex2()));
+}
+
+static ex tan_series(const ex &x,
+ const relational &rel,
+ int order,
+ unsigned options)
+{
+ GINAC_ASSERT(is_ex_exactly_of_type(rel.lhs(),symbol));
+ // method:
+ // Taylor series where there is no pole falls back to tan_deriv.
+ // On a pole simply expand sin(x)/cos(x).
+ const ex x_pt = x.subs(rel);
+ if (!(2*x_pt/Pi).info(info_flags::odd))
+ throw do_taylor(); // caught by function::series()
+ // if we got here we have to care for a simple pole
+ return (sin(x)/cos(x)).series(rel, order+2, options);
+}
+
+REGISTER_FUNCTION(tan, eval_func(tan_eval).
+ evalf_func(tan_evalf).
+ derivative_func(tan_deriv).
+ series_func(tan_series));