-static ex tan_evalf(ex const & x)
-{
- BEGIN_TYPECHECK
- TYPECHECK(x,numeric)
- END_TYPECHECK(tan(x)) // -> numeric tan(numeric)
-
- return tan(ex_to_numeric(x));
-}
-
-static ex tan_eval(ex const & 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 (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(_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_diff(ex const & x, unsigned diff_param)
-{
- GINAC_ASSERT(diff_param==0);
-
- // d/dx tan(x) -> 1+tan(x)^2;
- return (_ex1()+power(tan(x),_ex2()));
-}
-
-static ex tan_series(ex const & x, symbol const & s, ex const & point, int order)
-{
- // method:
- // Taylor series where there is no pole falls back to tan_diff.
- // On a pole simply expand sin(x)/cos(x).
- ex xpoint = x.subs(s==point);
- if (!(2*xpoint/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(s, point, order+2);
-}
-
-REGISTER_FUNCTION(tan, tan_eval, tan_evalf, tan_diff, tan_series);
+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));