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=(2*x)/(Pi*I);
61 if (TwoExOverPiI.info(info_flags::integer)) {
62 numeric z=mod(ex_to_numeric(TwoExOverPiI),numeric(4));
63 if (z.is_equal(numZERO()))
65 if (z.is_equal(numONE()))
67 if (z.is_equal(numTWO()))
69 if (z.is_equal(numTHREE()))
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);
90 REGISTER_FUNCTION(exp, exp_eval, exp_evalf, exp_diff, NULL);
96 static ex log_evalf(ex const & x)
100 END_TYPECHECK(log(x))
102 return log(ex_to_numeric(x)); // -> numeric log(numeric)
105 static ex log_eval(ex const & x)
107 if (x.info(info_flags::numeric)) {
109 if (x.is_equal(exONE()))
112 if (x.is_equal(exMINUSONE()))
116 return (I*Pi*numeric(1,2));
117 // log(-I) -> -Pi*I/2
119 return (I*Pi*numeric(-1,2));
120 // log(0) -> throw singularity
121 if (x.is_equal(exZERO()))
122 throw(std::domain_error("log_eval(): log(0)"));
124 if (!x.info(info_flags::crational))
127 // log(exp(t)) -> t (for real-valued t):
128 if (is_ex_the_function(x, exp)) {
130 if (t.info(info_flags::real))
134 return log(x).hold();
137 static ex log_diff(ex const & x, unsigned diff_param)
139 GINAC_ASSERT(diff_param==0);
144 REGISTER_FUNCTION(log, log_eval, log_evalf, log_diff, NULL);
147 // sine (trigonometric function)
150 static ex sin_evalf(ex const & x)
154 END_TYPECHECK(sin(x))
156 return sin(ex_to_numeric(x)); // -> numeric sin(numeric)
159 static ex sin_eval(ex const & x)
162 if (xOverPi.info(info_flags::numeric)) {
164 if (xOverPi.info(info_flags::integer))
167 // sin((2n+1)*Pi/2) -> {+|-}1
168 ex xOverPiMinusHalf=xOverPi-exHALF();
169 if (xOverPiMinusHalf.info(info_flags::even))
171 else if (xOverPiMinusHalf.info(info_flags::odd))
175 if (is_ex_exactly_of_type(x, function)) {
178 if (is_ex_the_function(x, asin))
180 // sin(acos(x)) -> (1-x^2)^(1/2)
181 if (is_ex_the_function(x, acos))
182 return power(exONE()-power(t,exTWO()),exHALF());
183 // sin(atan(x)) -> x*(1+x^2)^(-1/2)
184 if (is_ex_the_function(x, atan))
185 return t*power(exONE()+power(t,exTWO()),exMINUSHALF());
188 // sin(float) -> float
189 if (x.info(info_flags::numeric) && !x.info(info_flags::crational))
192 return sin(x).hold();
195 static ex sin_diff(ex const & x, unsigned diff_param)
197 GINAC_ASSERT(diff_param==0);
202 REGISTER_FUNCTION(sin, sin_eval, sin_evalf, sin_diff, NULL);
205 // cosine (trigonometric function)
208 static ex cos_evalf(ex const & x)
212 END_TYPECHECK(cos(x))
214 return cos(ex_to_numeric(x)); // -> numeric cos(numeric)
217 static ex cos_eval(ex const & x)
220 if (xOverPi.info(info_flags::numeric)) {
221 // cos(n*Pi) -> {+|-}1
222 if (xOverPi.info(info_flags::even))
224 else if (xOverPi.info(info_flags::odd))
227 // cos((2n+1)*Pi/2) -> 0
228 ex xOverPiMinusHalf=xOverPi-exHALF();
229 if (xOverPiMinusHalf.info(info_flags::integer))
233 if (is_ex_exactly_of_type(x, function)) {
236 if (is_ex_the_function(x, acos))
238 // cos(asin(x)) -> (1-x^2)^(1/2)
239 if (is_ex_the_function(x, asin))
240 return power(exONE()-power(t,exTWO()),exHALF());
241 // cos(atan(x)) -> (1+x^2)^(-1/2)
242 if (is_ex_the_function(x, atan))
243 return power(exONE()+power(t,exTWO()),exMINUSHALF());
246 // cos(float) -> float
247 if (x.info(info_flags::numeric) && !x.info(info_flags::crational))
250 return cos(x).hold();
253 static ex cos_diff(ex const & x, unsigned diff_param)
255 GINAC_ASSERT(diff_param==0);
257 return numMINUSONE()*sin(x);
260 REGISTER_FUNCTION(cos, cos_eval, cos_evalf, cos_diff, NULL);
263 // tangent (trigonometric function)
266 static ex tan_evalf(ex const & x)
270 END_TYPECHECK(tan(x)) // -> numeric tan(numeric)
272 return tan(ex_to_numeric(x));
275 static ex tan_eval(ex const & x)
277 // tan(n*Pi/3) -> {0|3^(1/2)|-(3^(1/2))}
278 ex ThreeExOverPi=numTHREE()*x/Pi;
279 if (ThreeExOverPi.info(info_flags::integer)) {
280 numeric z=mod(ex_to_numeric(ThreeExOverPi),numeric(3));
281 if (z.is_equal(numZERO()))
283 if (z.is_equal(numONE()))
284 return power(exTHREE(),exHALF());
285 if (z.is_equal(numTWO()))
286 return -power(exTHREE(),exHALF());
289 // tan((2n+1)*Pi/2) -> throw
290 ex ExOverPiMinusHalf=x/Pi-exHALF();
291 if (ExOverPiMinusHalf.info(info_flags::integer))
292 throw (std::domain_error("tan_eval(): infinity"));
294 if (is_ex_exactly_of_type(x, function)) {
297 if (is_ex_the_function(x, atan))
299 // tan(asin(x)) -> x*(1+x^2)^(-1/2)
300 if (is_ex_the_function(x, asin))
301 return t*power(exONE()-power(t,exTWO()),exMINUSHALF());
302 // tan(acos(x)) -> (1-x^2)^(1/2)/x
303 if (is_ex_the_function(x, acos))
304 return power(t,exMINUSONE())*power(exONE()-power(t,exTWO()),exHALF());
307 // tan(float) -> float
308 if (x.info(info_flags::numeric) && !x.info(info_flags::crational)) {
312 return tan(x).hold();
315 static ex tan_diff(ex const & x, unsigned diff_param)
317 GINAC_ASSERT(diff_param==0);
319 return (1+power(tan(x),exTWO()));
322 static ex tan_series(ex const & x, symbol const & s, ex const & point, int order)
325 // Taylor series where there is no pole falls back to tan_diff.
326 // On a pole simply expand sin(x)/cos(x).
327 ex xpoint = x.subs(s==point);
328 if (!(2*xpoint/Pi).info(info_flags::odd))
330 // if we got here we have to care for a simple pole
331 return (sin(x)/cos(x)).series(s, point, order+2);
334 REGISTER_FUNCTION(tan, tan_eval, tan_evalf, tan_diff, tan_series);
337 // inverse sine (arc sine)
340 static ex asin_evalf(ex const & x)
344 END_TYPECHECK(asin(x))
346 return asin(ex_to_numeric(x)); // -> numeric asin(numeric)
349 static ex asin_eval(ex const & x)
351 if (x.info(info_flags::numeric)) {
356 if (x.is_equal(exHALF()))
357 return numeric(1,6)*Pi;
359 if (x.is_equal(exONE()))
360 return numeric(1,2)*Pi;
361 // asin(-1/2) -> -Pi/6
362 if (x.is_equal(exMINUSHALF()))
363 return numeric(-1,6)*Pi;
365 if (x.is_equal(exMINUSONE()))
366 return numeric(-1,2)*Pi;
367 // asin(float) -> float
368 if (!x.info(info_flags::crational))
369 return asin_evalf(x);
372 return asin(x).hold();
375 static ex asin_diff(ex const & x, unsigned diff_param)
377 GINAC_ASSERT(diff_param==0);
379 return power(1-power(x,exTWO()),exMINUSHALF());
382 REGISTER_FUNCTION(asin, asin_eval, asin_evalf, asin_diff, NULL);
385 // inverse cosine (arc cosine)
388 static ex acos_evalf(ex const & x)
392 END_TYPECHECK(acos(x))
394 return acos(ex_to_numeric(x)); // -> numeric acos(numeric)
397 static ex acos_eval(ex const & x)
399 if (x.info(info_flags::numeric)) {
401 if (x.is_equal(exONE()))
404 if (x.is_equal(exHALF()))
405 return numeric(1,3)*Pi;
408 return numeric(1,2)*Pi;
409 // acos(-1/2) -> 2/3*Pi
410 if (x.is_equal(exMINUSHALF()))
411 return numeric(2,3)*Pi;
413 if (x.is_equal(exMINUSONE()))
415 // acos(float) -> float
416 if (!x.info(info_flags::crational))
417 return acos_evalf(x);
420 return acos(x).hold();
423 static ex acos_diff(ex const & x, unsigned diff_param)
425 GINAC_ASSERT(diff_param==0);
427 return numMINUSONE()*power(1-power(x,exTWO()),exMINUSHALF());
430 REGISTER_FUNCTION(acos, acos_eval, acos_evalf, acos_diff, NULL);
433 // inverse tangent (arc tangent)
436 static ex atan_evalf(ex const & x)
440 END_TYPECHECK(atan(x))
442 return atan(ex_to_numeric(x)); // -> numeric atan(numeric)
445 static ex atan_eval(ex const & x)
447 if (x.info(info_flags::numeric)) {
449 if (x.is_equal(exZERO()))
451 // atan(float) -> float
452 if (!x.info(info_flags::crational))
453 return atan_evalf(x);
456 return atan(x).hold();
459 static ex atan_diff(ex const & x, unsigned diff_param)
461 GINAC_ASSERT(diff_param==0);
463 return power(1+x*x, -1);
466 REGISTER_FUNCTION(atan, atan_eval, atan_evalf, atan_diff, NULL);
469 // inverse tangent (atan2(y,x))
472 static ex atan2_evalf(ex const & y, ex const & x)
477 END_TYPECHECK(atan2(y,x))
479 return atan(ex_to_numeric(y),ex_to_numeric(x)); // -> numeric atan(numeric)
482 static ex atan2_eval(ex const & y, ex const & x)
484 if (y.info(info_flags::numeric) && !y.info(info_flags::crational) &&
485 x.info(info_flags::numeric) && !x.info(info_flags::crational)) {
486 return atan2_evalf(y,x);
489 return atan2(y,x).hold();
492 static ex atan2_diff(ex const & y, ex const & x, unsigned diff_param)
494 GINAC_ASSERT(diff_param<2);
498 return x*pow(pow(x,2)+pow(y,2),-1);
501 return -y*pow(pow(x,2)+pow(y,2),-1);
504 REGISTER_FUNCTION(atan2, atan2_eval, atan2_evalf, atan2_diff, NULL);
507 // hyperbolic sine (trigonometric function)
510 static ex sinh_evalf(ex const & x)
514 END_TYPECHECK(sinh(x))
516 return sinh(ex_to_numeric(x)); // -> numeric sinh(numeric)
519 static ex sinh_eval(ex const & x)
521 if (x.info(info_flags::numeric)) {
525 // sinh(float) -> float
526 if (!x.info(info_flags::crational))
527 return sinh_evalf(x);
531 if (xOverPiI.info(info_flags::numeric)) {
533 if (xOverPiI.info(info_flags::integer))
536 // sinh((2n+1)*Pi*I/2) -> {+|-}I
537 ex xOverPiIMinusHalf=xOverPiI-exHALF();
538 if (xOverPiIMinusHalf.info(info_flags::even))
540 else if (xOverPiIMinusHalf.info(info_flags::odd))
544 if (is_ex_exactly_of_type(x, function)) {
546 // sinh(asinh(x)) -> x
547 if (is_ex_the_function(x, asinh))
549 // sinh(acosh(x)) -> (x-1)^(1/2) * (x+1)^(1/2)
550 if (is_ex_the_function(x, acosh))
551 return power(t-exONE(),exHALF())*power(t+exONE(),exHALF());
552 // sinh(atanh(x)) -> x*(1-x^2)^(-1/2)
553 if (is_ex_the_function(x, atanh))
554 return t*power(exONE()-power(t,exTWO()),exMINUSHALF());
557 return sinh(x).hold();
560 static ex sinh_diff(ex const & x, unsigned diff_param)
562 GINAC_ASSERT(diff_param==0);
567 REGISTER_FUNCTION(sinh, sinh_eval, sinh_evalf, sinh_diff, NULL);
570 // hyperbolic cosine (trigonometric function)
573 static ex cosh_evalf(ex const & x)
577 END_TYPECHECK(cosh(x))
579 return cosh(ex_to_numeric(x)); // -> numeric cosh(numeric)
582 static ex cosh_eval(ex const & x)
584 if (x.info(info_flags::numeric)) {
588 // cosh(float) -> float
589 if (!x.info(info_flags::crational))
590 return cosh_evalf(x);
594 if (xOverPiI.info(info_flags::numeric)) {
595 // cosh(n*Pi*I) -> {+|-}1
596 if (xOverPiI.info(info_flags::even))
598 else if (xOverPiI.info(info_flags::odd))
601 // cosh((2n+1)*Pi*I/2) -> 0
602 ex xOverPiIMinusHalf=xOverPiI-exHALF();
603 if (xOverPiIMinusHalf.info(info_flags::integer))
607 if (is_ex_exactly_of_type(x, function)) {
609 // cosh(acosh(x)) -> x
610 if (is_ex_the_function(x, acosh))
612 // cosh(asinh(x)) -> (1+x^2)^(1/2)
613 if (is_ex_the_function(x, asinh))
614 return power(exONE()+power(t,exTWO()),exHALF());
615 // cosh(atanh(x)) -> (1-x^2)^(-1/2)
616 if (is_ex_the_function(x, atanh))
617 return power(exONE()-power(t,exTWO()),exMINUSHALF());
620 return cosh(x).hold();
623 static ex cosh_diff(ex const & x, unsigned diff_param)
625 GINAC_ASSERT(diff_param==0);
630 REGISTER_FUNCTION(cosh, cosh_eval, cosh_evalf, cosh_diff, NULL);
633 // hyperbolic tangent (trigonometric function)
636 static ex tanh_evalf(ex const & x)
640 END_TYPECHECK(tanh(x))
642 return tanh(ex_to_numeric(x)); // -> numeric tanh(numeric)
645 static ex tanh_eval(ex const & x)
647 if (x.info(info_flags::numeric)) {
651 // tanh(float) -> float
652 if (!x.info(info_flags::crational))
653 return tanh_evalf(x);
656 if (is_ex_exactly_of_type(x, function)) {
658 // tanh(atanh(x)) -> x
659 if (is_ex_the_function(x, atanh))
661 // tanh(asinh(x)) -> x*(1+x^2)^(-1/2)
662 if (is_ex_the_function(x, asinh))
663 return t*power(exONE()+power(t,exTWO()),exMINUSHALF());
664 // tanh(acosh(x)) -> (x-1)^(1/2)*(x+1)^(1/2)/x
665 if (is_ex_the_function(x, acosh))
666 return power(t-exONE(),exHALF())*power(t+exONE(),exHALF())*power(t,exMINUSONE());
669 return tanh(x).hold();
672 static ex tanh_diff(ex const & x, unsigned diff_param)
674 GINAC_ASSERT(diff_param==0);
676 return exONE()-power(tanh(x),exTWO());
679 static ex tanh_series(ex const & x, symbol const & s, ex const & point, int order)
682 // Taylor series where there is no pole falls back to tanh_diff.
683 // On a pole simply expand sinh(x)/cosh(x).
684 ex xpoint = x.subs(s==point);
685 if (!(2*I*xpoint/Pi).info(info_flags::odd))
687 // if we got here we have to care for a simple pole
688 return (sinh(x)/cosh(x)).series(s, point, order+2);
691 REGISTER_FUNCTION(tanh, tanh_eval, tanh_evalf, tanh_diff, tanh_series);
694 // inverse hyperbolic sine (trigonometric function)
697 static ex asinh_evalf(ex const & x)
701 END_TYPECHECK(asinh(x))
703 return asinh(ex_to_numeric(x)); // -> numeric asinh(numeric)
706 static ex asinh_eval(ex const & x)
708 if (x.info(info_flags::numeric)) {
712 // asinh(float) -> float
713 if (!x.info(info_flags::crational))
714 return asinh_evalf(x);
717 return asinh(x).hold();
720 static ex asinh_diff(ex const & x, unsigned diff_param)
722 GINAC_ASSERT(diff_param==0);
724 return power(1+power(x,exTWO()),exMINUSHALF());
727 REGISTER_FUNCTION(asinh, asinh_eval, asinh_evalf, asinh_diff, NULL);
730 // inverse hyperbolic cosine (trigonometric function)
733 static ex acosh_evalf(ex const & x)
737 END_TYPECHECK(acosh(x))
739 return acosh(ex_to_numeric(x)); // -> numeric acosh(numeric)
742 static ex acosh_eval(ex const & x)
744 if (x.info(info_flags::numeric)) {
745 // acosh(0) -> Pi*I/2
747 return Pi*I*numeric(1,2);
749 if (x.is_equal(exONE()))
752 if (x.is_equal(exMINUSONE()))
754 // acosh(float) -> float
755 if (!x.info(info_flags::crational))
756 return acosh_evalf(x);
759 return acosh(x).hold();
762 static ex acosh_diff(ex const & x, unsigned diff_param)
764 GINAC_ASSERT(diff_param==0);
766 return power(x-1,exMINUSHALF())*power(x+1,exMINUSHALF());
769 REGISTER_FUNCTION(acosh, acosh_eval, acosh_evalf, acosh_diff, NULL);
772 // inverse hyperbolic tangent (trigonometric function)
775 static ex atanh_evalf(ex const & x)
779 END_TYPECHECK(atanh(x))
781 return atanh(ex_to_numeric(x)); // -> numeric atanh(numeric)
784 static ex atanh_eval(ex const & x)
786 if (x.info(info_flags::numeric)) {
790 // atanh({+|-}1) -> throw
791 if (x.is_equal(exONE()) || x.is_equal(exONE()))
792 throw (std::domain_error("atanh_eval(): infinity"));
793 // atanh(float) -> float
794 if (!x.info(info_flags::crational))
795 return atanh_evalf(x);
798 return atanh(x).hold();
801 static ex atanh_diff(ex const & x, unsigned diff_param)
803 GINAC_ASSERT(diff_param==0);
805 return power(exONE()-power(x,exTWO()),exMINUSONE());
808 REGISTER_FUNCTION(atanh, atanh_eval, atanh_evalf, atanh_diff, NULL);
810 #ifndef NO_GINAC_NAMESPACE
812 #endif // ndef NO_GINAC_NAMESPACE