1 /** @file inifcns_trans.cpp
3 * Implementation of transcendental (and trigonometric and hyperbolic)
7 * GiNaC Copyright (C) 1999 Johannes Gutenberg University Mainz, Germany
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
32 #include "relational.h"
36 #ifndef NO_GINAC_NAMESPACE
38 #endif // ndef NO_GINAC_NAMESPACE
41 // exponential function
44 static ex exp_evalf(ex const & x)
50 return exp(ex_to_numeric(x)); // -> numeric exp(numeric)
53 static ex exp_eval(ex const & x)
59 // exp(n*Pi*I/2) -> {+1|+I|-1|-I}
60 ex TwoExOverPiI=(_ex2()*x)/(Pi*I);
61 if (TwoExOverPiI.info(info_flags::integer)) {
62 numeric z=mod(ex_to_numeric(TwoExOverPiI),_num4());
63 if (z.is_equal(_num0()))
65 if (z.is_equal(_num1()))
67 if (z.is_equal(_num2()))
69 if (z.is_equal(_num3()))
73 if (is_ex_the_function(x, log))
77 if (x.info(info_flags::numeric) && !x.info(info_flags::crational))
83 static ex exp_diff(ex const & x, unsigned diff_param)
85 GINAC_ASSERT(diff_param==0);
87 // d/dx exp(x) -> exp(x)
91 REGISTER_FUNCTION(exp, exp_eval, exp_evalf, exp_diff, NULL);
97 static ex log_evalf(ex const & x)
101 END_TYPECHECK(log(x))
103 return log(ex_to_numeric(x)); // -> numeric log(numeric)
106 static ex log_eval(ex const & x)
108 if (x.info(info_flags::numeric)) {
109 if (x.is_equal(_ex1())) // log(1) -> 0
111 if (x.is_equal(_ex_1())) // log(-1) -> I*Pi
113 if (x.is_equal(I)) // log(I) -> Pi*I/2
114 return (Pi*I*_num1_2());
115 if (x.is_equal(-I)) // log(-I) -> -Pi*I/2
116 return (Pi*I*_num_1_2());
117 if (x.is_equal(_ex0())) // log(0) -> infinity
118 throw(std::domain_error("log_eval(): log(0)"));
120 if (!x.info(info_flags::crational))
123 // log(exp(t)) -> t (for real-valued t):
124 if (is_ex_the_function(x, exp)) {
126 if (t.info(info_flags::real))
130 return log(x).hold();
133 static ex log_diff(ex const & x, unsigned diff_param)
135 GINAC_ASSERT(diff_param==0);
137 // d/dx log(x) -> 1/x
138 return power(x, _ex_1());
141 REGISTER_FUNCTION(log, log_eval, log_evalf, log_diff, NULL);
144 // sine (trigonometric function)
147 static ex sin_evalf(ex const & x)
151 END_TYPECHECK(sin(x))
153 return sin(ex_to_numeric(x)); // -> numeric sin(numeric)
156 static ex sin_eval(ex const & x)
158 // sin(n/d*Pi) -> { all known non-nested radicals }
159 ex SixtyExOverPi = _ex60()*x/Pi;
161 if (SixtyExOverPi.info(info_flags::integer)) {
162 numeric z = mod(ex_to_numeric(SixtyExOverPi),_num120());
164 // wrap to interval [0, Pi)
169 // wrap to interval [0, Pi/2)
172 if (z.is_equal(_num0())) // sin(0) -> 0
174 if (z.is_equal(_num5())) // sin(Pi/12) -> sqrt(6)/4*(1-sqrt(3)/3)
175 return sign*_ex1_4()*power(_ex6(),_ex1_2())*(_ex1()+_ex_1_3()*power(_ex3(),_ex1_2()));
176 if (z.is_equal(_num6())) // sin(Pi/10) -> sqrt(5)/4-1/4
177 return sign*(_ex1_4()*power(_ex5(),_ex1_2())+_ex_1_4());
178 if (z.is_equal(_num10())) // sin(Pi/6) -> 1/2
179 return sign*_ex1_2();
180 if (z.is_equal(_num15())) // sin(Pi/4) -> sqrt(2)/2
181 return sign*_ex1_2()*power(_ex2(),_ex1_2());
182 if (z.is_equal(_num18())) // sin(3/10*Pi) -> sqrt(5)/4+1/4
183 return sign*(_ex1_4()*power(_ex5(),_ex1_2())+_ex1_4());
184 if (z.is_equal(_num20())) // sin(Pi/3) -> sqrt(3)/2
185 return sign*_ex1_2()*power(_ex3(),_ex1_2());
186 if (z.is_equal(_num25())) // sin(5/12*Pi) -> sqrt(6)/4*(1+sqrt(3)/3)
187 return sign*_ex1_4()*power(_ex6(),_ex1_2())*(_ex1()+_ex1_3()*power(_ex3(),_ex1_2()));
188 if (z.is_equal(_num30())) // sin(Pi/2) -> 1
192 if (is_ex_exactly_of_type(x, function)) {
195 if (is_ex_the_function(x, asin))
197 // sin(acos(x)) -> sqrt(1-x^2)
198 if (is_ex_the_function(x, acos))
199 return power(_ex1()-power(t,_ex2()),_ex1_2());
200 // sin(atan(x)) -> x*(1+x^2)^(-1/2)
201 if (is_ex_the_function(x, atan))
202 return t*power(_ex1()+power(t,_ex2()),_ex_1_2());
205 // sin(float) -> float
206 if (x.info(info_flags::numeric) && !x.info(info_flags::crational))
209 return sin(x).hold();
212 static ex sin_diff(ex const & x, unsigned diff_param)
214 GINAC_ASSERT(diff_param==0);
216 // d/dx sin(x) -> cos(x)
220 REGISTER_FUNCTION(sin, sin_eval, sin_evalf, sin_diff, NULL);
223 // cosine (trigonometric function)
226 static ex cos_evalf(ex const & x)
230 END_TYPECHECK(cos(x))
232 return cos(ex_to_numeric(x)); // -> numeric cos(numeric)
235 static ex cos_eval(ex const & x)
237 // cos(n/d*Pi) -> { all known non-nested radicals }
238 ex SixtyExOverPi = _ex60()*x/Pi;
240 if (SixtyExOverPi.info(info_flags::integer)) {
241 numeric z = mod(ex_to_numeric(SixtyExOverPi),_num120());
243 // wrap to interval [0, Pi)
247 // wrap to interval [0, Pi/2)
251 if (z.is_equal(_num0())) // cos(0) -> 1
253 if (z.is_equal(_num5())) // cos(Pi/12) -> sqrt(6)/4*(1+sqrt(3)/3)
254 return sign*_ex1_4()*power(_ex6(),_ex1_2())*(_ex1()+_ex1_3()*power(_ex3(),_ex1_2()));
255 if (z.is_equal(_num10())) // cos(Pi/6) -> sqrt(3)/2
256 return sign*_ex1_2()*power(_ex3(),_ex1_2());
257 if (z.is_equal(_num12())) // cos(Pi/5) -> sqrt(5)/4+1/4
258 return sign*(_ex1_4()*power(_ex5(),_ex1_2())+_ex1_4());
259 if (z.is_equal(_num15())) // cos(Pi/4) -> sqrt(2)/2
260 return sign*_ex1_2()*power(_ex2(),_ex1_2());
261 if (z.is_equal(_num20())) // cos(Pi/3) -> 1/2
262 return sign*_ex1_2();
263 if (z.is_equal(_num24())) // cos(2/5*Pi) -> sqrt(5)/4-1/4x
264 return sign*(_ex1_4()*power(_ex5(),_ex1_2())+_ex_1_4());
265 if (z.is_equal(_num25())) // cos(5/12*Pi) -> sqrt(6)/4*(1-sqrt(3)/3)
266 return sign*_ex1_4()*power(_ex6(),_ex1_2())*(_ex1()+_ex_1_3()*power(_ex3(),_ex1_2()));
267 if (z.is_equal(_num30())) // cos(Pi/2) -> 0
271 if (is_ex_exactly_of_type(x, function)) {
274 if (is_ex_the_function(x, acos))
276 // cos(asin(x)) -> (1-x^2)^(1/2)
277 if (is_ex_the_function(x, asin))
278 return power(_ex1()-power(t,_ex2()),_ex1_2());
279 // cos(atan(x)) -> (1+x^2)^(-1/2)
280 if (is_ex_the_function(x, atan))
281 return power(_ex1()+power(t,_ex2()),_ex_1_2());
284 // cos(float) -> float
285 if (x.info(info_flags::numeric) && !x.info(info_flags::crational))
288 return cos(x).hold();
291 static ex cos_diff(ex const & x, unsigned diff_param)
293 GINAC_ASSERT(diff_param==0);
295 // d/dx cos(x) -> -sin(x)
296 return _ex_1()*sin(x);
299 REGISTER_FUNCTION(cos, cos_eval, cos_evalf, cos_diff, NULL);
302 // tangent (trigonometric function)
305 static ex tan_evalf(ex const & x)
309 END_TYPECHECK(tan(x)) // -> numeric tan(numeric)
311 return tan(ex_to_numeric(x));
314 static ex tan_eval(ex const & x)
316 // tan(n/d*Pi) -> { all known non-nested radicals }
317 ex SixtyExOverPi = _ex60()*x/Pi;
319 if (SixtyExOverPi.info(info_flags::integer)) {
320 numeric z = mod(ex_to_numeric(SixtyExOverPi),_num60());
322 // wrap to interval [0, Pi)
326 // wrap to interval [0, Pi/2)
330 if (z.is_equal(_num0())) // tan(0) -> 0
332 if (z.is_equal(_num5())) // tan(Pi/12) -> 2-sqrt(3)
333 return sign*(_ex2()-power(_ex3(),_ex1_2()));
334 if (z.is_equal(_num10())) // tan(Pi/6) -> sqrt(3)/3
335 return sign*_ex1_3()*power(_ex3(),_ex1_2());
336 if (z.is_equal(_num15())) // tan(Pi/4) -> 1
338 if (z.is_equal(_num20())) // tan(Pi/3) -> sqrt(3)
339 return sign*power(_ex3(),_ex1_2());
340 if (z.is_equal(_num25())) // tan(5/12*Pi) -> 2+sqrt(3)
341 return sign*(power(_ex3(),_ex1_2())+_ex2());
342 if (z.is_equal(_num30())) // tan(Pi/2) -> infinity
343 throw (std::domain_error("tan_eval(): infinity"));
346 if (is_ex_exactly_of_type(x, function)) {
349 if (is_ex_the_function(x, atan))
351 // tan(asin(x)) -> x*(1+x^2)^(-1/2)
352 if (is_ex_the_function(x, asin))
353 return t*power(_ex1()-power(t,_ex2()),_ex_1_2());
354 // tan(acos(x)) -> (1-x^2)^(1/2)/x
355 if (is_ex_the_function(x, acos))
356 return power(t,_ex_1())*power(_ex1()-power(t,_ex2()),_ex1_2());
359 // tan(float) -> float
360 if (x.info(info_flags::numeric) && !x.info(info_flags::crational)) {
364 return tan(x).hold();
367 static ex tan_diff(ex const & x, unsigned diff_param)
369 GINAC_ASSERT(diff_param==0);
371 // d/dx tan(x) -> 1+tan(x)^2;
372 return (_ex1()+power(tan(x),_ex2()));
375 static ex tan_series(ex const & x, symbol const & s, ex const & point, int order)
378 // Taylor series where there is no pole falls back to tan_diff.
379 // On a pole simply expand sin(x)/cos(x).
380 ex xpoint = x.subs(s==point);
381 if (!(2*xpoint/Pi).info(info_flags::odd))
382 throw do_taylor(); // caught by function::series()
383 // if we got here we have to care for a simple pole
384 return (sin(x)/cos(x)).series(s, point, order+2);
387 REGISTER_FUNCTION(tan, tan_eval, tan_evalf, tan_diff, tan_series);
390 // inverse sine (arc sine)
393 static ex asin_evalf(ex const & x)
397 END_TYPECHECK(asin(x))
399 return asin(ex_to_numeric(x)); // -> numeric asin(numeric)
402 static ex asin_eval(ex const & x)
404 if (x.info(info_flags::numeric)) {
409 if (x.is_equal(_ex1_2()))
410 return numeric(1,6)*Pi;
412 if (x.is_equal(_ex1()))
414 // asin(-1/2) -> -Pi/6
415 if (x.is_equal(_ex_1_2()))
416 return numeric(-1,6)*Pi;
418 if (x.is_equal(_ex_1()))
419 return _num_1_2()*Pi;
420 // asin(float) -> float
421 if (!x.info(info_flags::crational))
422 return asin_evalf(x);
425 return asin(x).hold();
428 static ex asin_diff(ex const & x, unsigned diff_param)
430 GINAC_ASSERT(diff_param==0);
432 // d/dx asin(x) -> 1/sqrt(1-x^2)
433 return power(1-power(x,_ex2()),_ex_1_2());
436 REGISTER_FUNCTION(asin, asin_eval, asin_evalf, asin_diff, NULL);
439 // inverse cosine (arc cosine)
442 static ex acos_evalf(ex const & x)
446 END_TYPECHECK(acos(x))
448 return acos(ex_to_numeric(x)); // -> numeric acos(numeric)
451 static ex acos_eval(ex const & x)
453 if (x.info(info_flags::numeric)) {
455 if (x.is_equal(_ex1()))
458 if (x.is_equal(_ex1_2()))
463 // acos(-1/2) -> 2/3*Pi
464 if (x.is_equal(_ex_1_2()))
465 return numeric(2,3)*Pi;
467 if (x.is_equal(_ex_1()))
469 // acos(float) -> float
470 if (!x.info(info_flags::crational))
471 return acos_evalf(x);
474 return acos(x).hold();
477 static ex acos_diff(ex const & x, unsigned diff_param)
479 GINAC_ASSERT(diff_param==0);
481 // d/dx acos(x) -> -1/sqrt(1-x^2)
482 return _ex_1()*power(1-power(x,_ex2()),_ex_1_2());
485 REGISTER_FUNCTION(acos, acos_eval, acos_evalf, acos_diff, NULL);
488 // inverse tangent (arc tangent)
491 static ex atan_evalf(ex const & x)
495 END_TYPECHECK(atan(x))
497 return atan(ex_to_numeric(x)); // -> numeric atan(numeric)
500 static ex atan_eval(ex const & x)
502 if (x.info(info_flags::numeric)) {
504 if (x.is_equal(_ex0()))
506 // atan(float) -> float
507 if (!x.info(info_flags::crational))
508 return atan_evalf(x);
511 return atan(x).hold();
514 static ex atan_diff(ex const & x, unsigned diff_param)
516 GINAC_ASSERT(diff_param==0);
518 // d/dx atan(x) -> 1/(1+x^2)
519 return power(_ex1()+power(x,_ex2()), _ex_1());
522 REGISTER_FUNCTION(atan, atan_eval, atan_evalf, atan_diff, NULL);
525 // inverse tangent (atan2(y,x))
528 static ex atan2_evalf(ex const & y, ex const & x)
533 END_TYPECHECK(atan2(y,x))
535 return atan(ex_to_numeric(y),ex_to_numeric(x)); // -> numeric atan(numeric)
538 static ex atan2_eval(ex const & y, ex const & x)
540 if (y.info(info_flags::numeric) && !y.info(info_flags::crational) &&
541 x.info(info_flags::numeric) && !x.info(info_flags::crational)) {
542 return atan2_evalf(y,x);
545 return atan2(y,x).hold();
548 static ex atan2_diff(ex const & y, ex const & x, unsigned diff_param)
550 GINAC_ASSERT(diff_param<2);
554 return x*power(power(x,_ex2())+power(y,_ex2()),_ex_1());
557 return -y*power(power(x,_ex2())+power(y,_ex2()),_ex_1());
560 REGISTER_FUNCTION(atan2, atan2_eval, atan2_evalf, atan2_diff, NULL);
563 // hyperbolic sine (trigonometric function)
566 static ex sinh_evalf(ex const & x)
570 END_TYPECHECK(sinh(x))
572 return sinh(ex_to_numeric(x)); // -> numeric sinh(numeric)
575 static ex sinh_eval(ex const & x)
577 if (x.info(info_flags::numeric)) {
578 if (x.is_zero()) // sinh(0) -> 0
580 if (!x.info(info_flags::crational)) // sinh(float) -> float
581 return sinh_evalf(x);
584 if ((x/Pi).info(info_flags::numeric) &&
585 ex_to_numeric(x/Pi).real().is_zero()) // sinh(I*x) -> I*sin(x)
588 if (is_ex_exactly_of_type(x, function)) {
590 // sinh(asinh(x)) -> x
591 if (is_ex_the_function(x, asinh))
593 // sinh(acosh(x)) -> (x-1)^(1/2) * (x+1)^(1/2)
594 if (is_ex_the_function(x, acosh))
595 return power(t-_ex1(),_ex1_2())*power(t+_ex1(),_ex1_2());
596 // sinh(atanh(x)) -> x*(1-x^2)^(-1/2)
597 if (is_ex_the_function(x, atanh))
598 return t*power(_ex1()-power(t,_ex2()),_ex_1_2());
601 return sinh(x).hold();
604 static ex sinh_diff(ex const & x, unsigned diff_param)
606 GINAC_ASSERT(diff_param==0);
608 // d/dx sinh(x) -> cosh(x)
612 REGISTER_FUNCTION(sinh, sinh_eval, sinh_evalf, sinh_diff, NULL);
615 // hyperbolic cosine (trigonometric function)
618 static ex cosh_evalf(ex const & x)
622 END_TYPECHECK(cosh(x))
624 return cosh(ex_to_numeric(x)); // -> numeric cosh(numeric)
627 static ex cosh_eval(ex const & x)
629 if (x.info(info_flags::numeric)) {
630 if (x.is_zero()) // cosh(0) -> 1
632 if (!x.info(info_flags::crational)) // cosh(float) -> float
633 return cosh_evalf(x);
636 if ((x/Pi).info(info_flags::numeric) &&
637 ex_to_numeric(x/Pi).real().is_zero()) // cosh(I*x) -> cos(x)
640 if (is_ex_exactly_of_type(x, function)) {
642 // cosh(acosh(x)) -> x
643 if (is_ex_the_function(x, acosh))
645 // cosh(asinh(x)) -> (1+x^2)^(1/2)
646 if (is_ex_the_function(x, asinh))
647 return power(_ex1()+power(t,_ex2()),_ex1_2());
648 // cosh(atanh(x)) -> (1-x^2)^(-1/2)
649 if (is_ex_the_function(x, atanh))
650 return power(_ex1()-power(t,_ex2()),_ex_1_2());
653 return cosh(x).hold();
656 static ex cosh_diff(ex const & x, unsigned diff_param)
658 GINAC_ASSERT(diff_param==0);
660 // d/dx cosh(x) -> sinh(x)
664 REGISTER_FUNCTION(cosh, cosh_eval, cosh_evalf, cosh_diff, NULL);
667 // hyperbolic tangent (trigonometric function)
670 static ex tanh_evalf(ex const & x)
674 END_TYPECHECK(tanh(x))
676 return tanh(ex_to_numeric(x)); // -> numeric tanh(numeric)
679 static ex tanh_eval(ex const & x)
681 if (x.info(info_flags::numeric)) {
682 if (x.is_zero()) // tanh(0) -> 0
684 if (!x.info(info_flags::crational)) // tanh(float) -> float
685 return tanh_evalf(x);
688 if ((x/Pi).info(info_flags::numeric) &&
689 ex_to_numeric(x/Pi).real().is_zero()) // tanh(I*x) -> I*tan(x);
692 if (is_ex_exactly_of_type(x, function)) {
694 // tanh(atanh(x)) -> x
695 if (is_ex_the_function(x, atanh))
697 // tanh(asinh(x)) -> x*(1+x^2)^(-1/2)
698 if (is_ex_the_function(x, asinh))
699 return t*power(_ex1()+power(t,_ex2()),_ex_1_2());
700 // tanh(acosh(x)) -> (x-1)^(1/2)*(x+1)^(1/2)/x
701 if (is_ex_the_function(x, acosh))
702 return power(t-_ex1(),_ex1_2())*power(t+_ex1(),_ex1_2())*power(t,_ex_1());
705 return tanh(x).hold();
708 static ex tanh_diff(ex const & x, unsigned diff_param)
710 GINAC_ASSERT(diff_param==0);
712 // d/dx tanh(x) -> 1-tanh(x)^2
713 return _ex1()-power(tanh(x),_ex2());
716 static ex tanh_series(ex const & x, symbol const & s, ex const & point, int order)
719 // Taylor series where there is no pole falls back to tanh_diff.
720 // On a pole simply expand sinh(x)/cosh(x).
721 ex xpoint = x.subs(s==point);
722 if (!(2*I*xpoint/Pi).info(info_flags::odd))
723 throw do_taylor(); // caught by function::series()
724 // if we got here we have to care for a simple pole
725 return (sinh(x)/cosh(x)).series(s, point, order+2);
728 REGISTER_FUNCTION(tanh, tanh_eval, tanh_evalf, tanh_diff, tanh_series);
731 // inverse hyperbolic sine (trigonometric function)
734 static ex asinh_evalf(ex const & x)
738 END_TYPECHECK(asinh(x))
740 return asinh(ex_to_numeric(x)); // -> numeric asinh(numeric)
743 static ex asinh_eval(ex const & x)
745 if (x.info(info_flags::numeric)) {
749 // asinh(float) -> float
750 if (!x.info(info_flags::crational))
751 return asinh_evalf(x);
754 return asinh(x).hold();
757 static ex asinh_diff(ex const & x, unsigned diff_param)
759 GINAC_ASSERT(diff_param==0);
761 // d/dx asinh(x) -> 1/sqrt(1+x^2)
762 return power(_ex1()+power(x,_ex2()),_ex_1_2());
765 REGISTER_FUNCTION(asinh, asinh_eval, asinh_evalf, asinh_diff, NULL);
768 // inverse hyperbolic cosine (trigonometric function)
771 static ex acosh_evalf(ex const & x)
775 END_TYPECHECK(acosh(x))
777 return acosh(ex_to_numeric(x)); // -> numeric acosh(numeric)
780 static ex acosh_eval(ex const & x)
782 if (x.info(info_flags::numeric)) {
783 // acosh(0) -> Pi*I/2
785 return Pi*I*numeric(1,2);
787 if (x.is_equal(_ex1()))
790 if (x.is_equal(_ex_1()))
792 // acosh(float) -> float
793 if (!x.info(info_flags::crational))
794 return acosh_evalf(x);
797 return acosh(x).hold();
800 static ex acosh_diff(ex const & x, unsigned diff_param)
802 GINAC_ASSERT(diff_param==0);
804 // d/dx acosh(x) -> 1/(sqrt(x-1)*sqrt(x+1))
805 return power(x+_ex_1(),_ex_1_2())*power(x+_ex1(),_ex_1_2());
808 REGISTER_FUNCTION(acosh, acosh_eval, acosh_evalf, acosh_diff, NULL);
811 // inverse hyperbolic tangent (trigonometric function)
814 static ex atanh_evalf(ex const & x)
818 END_TYPECHECK(atanh(x))
820 return atanh(ex_to_numeric(x)); // -> numeric atanh(numeric)
823 static ex atanh_eval(ex const & x)
825 if (x.info(info_flags::numeric)) {
829 // atanh({+|-}1) -> throw
830 if (x.is_equal(_ex1()) || x.is_equal(_ex1()))
831 throw (std::domain_error("atanh_eval(): infinity"));
832 // atanh(float) -> float
833 if (!x.info(info_flags::crational))
834 return atanh_evalf(x);
837 return atanh(x).hold();
840 static ex atanh_diff(ex const & x, unsigned diff_param)
842 GINAC_ASSERT(diff_param==0);
844 // d/dx atanh(x) -> 1/(1-x^2)
845 return power(_ex1()-power(x,_ex2()),_ex_1());
848 REGISTER_FUNCTION(atanh, atanh_eval, atanh_evalf, atanh_diff, NULL);
850 #ifndef NO_GINAC_NAMESPACE
852 #endif // ndef NO_GINAC_NAMESPACE