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
36 // exponential function
39 static ex exp_evalf(ex const & x)
45 return exp(ex_to_numeric(x)); // -> numeric exp(numeric)
48 static ex exp_eval(ex const & x)
54 // exp(n*Pi*I/2) -> {+1|+I|-1|-I}
55 ex TwoExOverPiI=(2*x)/(Pi*I);
56 if (TwoExOverPiI.info(info_flags::integer)) {
57 numeric z=mod(ex_to_numeric(TwoExOverPiI),numeric(4));
58 if (z.is_equal(numZERO()))
60 if (z.is_equal(numONE()))
62 if (z.is_equal(numTWO()))
64 if (z.is_equal(numTHREE()))
68 if (is_ex_the_function(x, log))
72 if (x.info(info_flags::numeric) && !x.info(info_flags::rational))
78 static ex exp_diff(ex const & x, unsigned diff_param)
80 ASSERT(diff_param==0);
85 REGISTER_FUNCTION(exp, exp_eval, exp_evalf, exp_diff, NULL);
91 static ex log_evalf(ex const & x)
97 return log(ex_to_numeric(x)); // -> numeric log(numeric)
100 static ex log_eval(ex const & x)
102 if (x.info(info_flags::numeric)) {
104 if (x.is_equal(exONE()))
107 if (x.is_equal(exMINUSONE()))
111 return (I*Pi*numeric(1,2));
112 // log(-I) -> -Pi*I/2
114 return (I*Pi*numeric(-1,2));
115 // log(0) -> throw singularity
116 if (x.is_equal(exZERO()))
117 throw(std::domain_error("log_eval(): log(0)"));
119 if (!x.info(info_flags::rational))
123 return log(x).hold();
126 static ex log_diff(ex const & x, unsigned diff_param)
128 ASSERT(diff_param==0);
133 REGISTER_FUNCTION(log, log_eval, log_evalf, log_diff, NULL);
136 // sine (trigonometric function)
139 static ex sin_evalf(ex const & x)
143 END_TYPECHECK(sin(x))
145 return sin(ex_to_numeric(x)); // -> numeric sin(numeric)
148 static ex sin_eval(ex const & x)
152 if (xOverPi.info(info_flags::integer))
155 // sin((2n+1)*Pi/2) -> {+|-}1
156 ex xOverPiMinusHalf=xOverPi-exHALF();
157 if (xOverPiMinusHalf.info(info_flags::even))
159 else if (xOverPiMinusHalf.info(info_flags::odd))
162 if (is_ex_exactly_of_type(x, function)) {
165 if (is_ex_the_function(x, asin))
167 // sin(acos(x)) -> (1-x^2)^(1/2)
168 if (is_ex_the_function(x, acos))
169 return power(exONE()-power(t,exTWO()),exHALF());
170 // sin(atan(x)) -> x*(1+x^2)^(-1/2)
171 if (is_ex_the_function(x, atan))
172 return t*power(exONE()+power(t,exTWO()),exMINUSHALF());
175 // sin(float) -> float
176 if (x.info(info_flags::numeric) && !x.info(info_flags::rational))
179 return sin(x).hold();
182 static ex sin_diff(ex const & x, unsigned diff_param)
184 ASSERT(diff_param==0);
189 REGISTER_FUNCTION(sin, sin_eval, sin_evalf, sin_diff, NULL);
192 // cosine (trigonometric function)
195 static ex cos_evalf(ex const & x)
199 END_TYPECHECK(cos(x))
201 return cos(ex_to_numeric(x)); // -> numeric cos(numeric)
204 static ex cos_eval(ex const & x)
206 // cos(n*Pi) -> {+|-}1
208 if (xOverPi.info(info_flags::even))
210 else if (xOverPi.info(info_flags::odd))
213 // cos((2n+1)*Pi/2) -> 0
214 ex xOverPiMinusHalf=xOverPi-exHALF();
215 if (xOverPiMinusHalf.info(info_flags::integer))
218 if (is_ex_exactly_of_type(x, function)) {
221 if (is_ex_the_function(x, acos))
223 // cos(asin(x)) -> (1-x^2)^(1/2)
224 if (is_ex_the_function(x, asin))
225 return power(exONE()-power(t,exTWO()),exHALF());
226 // cos(atan(x)) -> (1+x^2)^(-1/2)
227 if (is_ex_the_function(x, atan))
228 return power(exONE()+power(t,exTWO()),exMINUSHALF());
231 // cos(float) -> float
232 if (x.info(info_flags::numeric) && !x.info(info_flags::rational))
235 return cos(x).hold();
238 static ex cos_diff(ex const & x, unsigned diff_param)
240 ASSERT(diff_param==0);
242 return numMINUSONE()*sin(x);
245 REGISTER_FUNCTION(cos, cos_eval, cos_evalf, cos_diff, NULL);
248 // tangent (trigonometric function)
251 static ex tan_evalf(ex const & x)
255 END_TYPECHECK(tan(x)) // -> numeric tan(numeric)
257 return tan(ex_to_numeric(x));
260 static ex tan_eval(ex const & x)
262 // tan(n*Pi/3) -> {0|3^(1/2)|-(3^(1/2))}
263 ex ThreeExOverPi=numTHREE()*x/Pi;
264 if (ThreeExOverPi.info(info_flags::integer)) {
265 numeric z=mod(ex_to_numeric(ThreeExOverPi),numeric(3));
266 if (z.is_equal(numZERO()))
268 if (z.is_equal(numONE()))
269 return power(exTHREE(),exHALF());
270 if (z.is_equal(numTWO()))
271 return -power(exTHREE(),exHALF());
274 // tan((2n+1)*Pi/2) -> throw
275 ex ExOverPiMinusHalf=x/Pi-exHALF();
276 if (ExOverPiMinusHalf.info(info_flags::integer))
277 throw (std::domain_error("tan_eval(): infinity"));
279 if (is_ex_exactly_of_type(x, function)) {
282 if (is_ex_the_function(x, atan))
284 // tan(asin(x)) -> x*(1+x^2)^(-1/2)
285 if (is_ex_the_function(x, asin))
286 return t*power(exONE()-power(t,exTWO()),exMINUSHALF());
287 // tan(acos(x)) -> (1-x^2)^(1/2)/x
288 if (is_ex_the_function(x, acos))
289 return power(t,exMINUSONE())*power(exONE()-power(t,exTWO()),exHALF());
292 // tan(float) -> float
293 if (x.info(info_flags::numeric) && !x.info(info_flags::rational)) {
297 return tan(x).hold();
300 static ex tan_diff(ex const & x, unsigned diff_param)
302 ASSERT(diff_param==0);
304 return (1+power(tan(x),exTWO()));
307 REGISTER_FUNCTION(tan, tan_eval, tan_evalf, tan_diff, NULL);
310 // inverse sine (arc sine)
313 static ex asin_evalf(ex const & x)
317 END_TYPECHECK(asin(x))
319 return asin(ex_to_numeric(x)); // -> numeric asin(numeric)
322 static ex asin_eval(ex const & x)
324 if (x.info(info_flags::numeric)) {
329 if (x.is_equal(exHALF()))
330 return numeric(1,6)*Pi;
332 if (x.is_equal(exONE()))
333 return numeric(1,2)*Pi;
334 // asin(-1/2) -> -Pi/6
335 if (x.is_equal(exMINUSHALF()))
336 return numeric(-1,6)*Pi;
338 if (x.is_equal(exMINUSONE()))
339 return numeric(-1,2)*Pi;
340 // asin(float) -> float
341 if (!x.info(info_flags::rational))
342 return asin_evalf(x);
345 return asin(x).hold();
348 static ex asin_diff(ex const & x, unsigned diff_param)
350 ASSERT(diff_param==0);
352 return power(1-power(x,exTWO()),exMINUSHALF());
355 REGISTER_FUNCTION(asin, asin_eval, asin_evalf, asin_diff, NULL);
358 // inverse cosine (arc cosine)
361 static ex acos_evalf(ex const & x)
365 END_TYPECHECK(acos(x))
367 return acos(ex_to_numeric(x)); // -> numeric acos(numeric)
370 static ex acos_eval(ex const & x)
372 if (x.info(info_flags::numeric)) {
374 if (x.is_equal(exONE()))
377 if (x.is_equal(exHALF()))
378 return numeric(1,3)*Pi;
381 return numeric(1,2)*Pi;
382 // acos(-1/2) -> 2/3*Pi
383 if (x.is_equal(exMINUSHALF()))
384 return numeric(2,3)*Pi;
386 if (x.is_equal(exMINUSONE()))
388 // acos(float) -> float
389 if (!x.info(info_flags::rational))
390 return acos_evalf(x);
393 return acos(x).hold();
396 static ex acos_diff(ex const & x, unsigned diff_param)
398 ASSERT(diff_param==0);
400 return numMINUSONE()*power(1-power(x,exTWO()),exMINUSHALF());
403 REGISTER_FUNCTION(acos, acos_eval, acos_evalf, acos_diff, NULL);
406 // inverse tangent (arc tangent)
409 static ex atan_evalf(ex const & x)
413 END_TYPECHECK(atan(x))
415 return atan(ex_to_numeric(x)); // -> numeric atan(numeric)
418 static ex atan_eval(ex const & x)
420 if (x.info(info_flags::numeric)) {
422 if (x.is_equal(exZERO()))
424 // atan(float) -> float
425 if (!x.info(info_flags::rational))
426 return atan_evalf(x);
429 return atan(x).hold();
432 static ex atan_diff(ex const & x, unsigned diff_param)
434 ASSERT(diff_param==0);
436 return power(1+x*x, -1);
439 REGISTER_FUNCTION(atan, atan_eval, atan_evalf, atan_diff, NULL);
442 // inverse tangent (atan2(y,x))
445 static ex atan2_evalf(ex const & y, ex const & x)
450 END_TYPECHECK(atan2(y,x))
452 return atan(ex_to_numeric(y),ex_to_numeric(x)); // -> numeric atan(numeric)
455 static ex atan2_eval(ex const & y, ex const & x)
457 if (y.info(info_flags::numeric) && !y.info(info_flags::rational) &&
458 x.info(info_flags::numeric) && !x.info(info_flags::rational)) {
459 return atan2_evalf(y,x);
462 return atan2(y,x).hold();
465 static ex atan2_diff(ex const & y, ex const & x, unsigned diff_param)
467 ASSERT(diff_param<2);
471 return pow(x*(1+y*y/(x*x)),-1);
474 return -y*pow(x*x+y*y,-1);
477 REGISTER_FUNCTION(atan2, atan2_eval, atan2_evalf, atan2_diff, NULL);
480 // hyperbolic sine (trigonometric function)
483 static ex sinh_evalf(ex const & x)
487 END_TYPECHECK(sinh(x))
489 return sinh(ex_to_numeric(x)); // -> numeric sinh(numeric)
492 static ex sinh_eval(ex const & x)
494 if (x.info(info_flags::numeric)) {
498 // sinh(float) -> float
499 if (!x.info(info_flags::rational))
500 return sinh_evalf(x);
503 if (is_ex_exactly_of_type(x, function)) {
505 // sinh(asinh(x)) -> x
506 if (is_ex_the_function(x, asinh))
508 // sinh(acosh(x)) -> (x-1)^(1/2) * (x+1)^(1/2)
509 if (is_ex_the_function(x, acosh))
510 return power(t-exONE(),exHALF())*power(t+exONE(),exHALF());
511 // sinh(atanh(x)) -> x*(1-x^2)^(-1/2)
512 if (is_ex_the_function(x, atanh))
513 return t*power(exONE()-power(t,exTWO()),exMINUSHALF());
516 return sinh(x).hold();
519 static ex sinh_diff(ex const & x, unsigned diff_param)
521 ASSERT(diff_param==0);
526 REGISTER_FUNCTION(sinh, sinh_eval, sinh_evalf, sinh_diff, NULL);
529 // hyperbolic cosine (trigonometric function)
532 static ex cosh_evalf(ex const & x)
536 END_TYPECHECK(cosh(x))
538 return cosh(ex_to_numeric(x)); // -> numeric cosh(numeric)
541 static ex cosh_eval(ex const & x)
543 if (x.info(info_flags::numeric)) {
547 // cosh(float) -> float
548 if (!x.info(info_flags::rational))
549 return cosh_evalf(x);
552 if (is_ex_exactly_of_type(x, function)) {
554 // cosh(acosh(x)) -> x
555 if (is_ex_the_function(x, acosh))
557 // cosh(asinh(x)) -> (1+x^2)^(1/2)
558 if (is_ex_the_function(x, asinh))
559 return power(exONE()+power(t,exTWO()),exHALF());
560 // cosh(atanh(x)) -> (1-x^2)^(-1/2)
561 if (is_ex_the_function(x, atanh))
562 return power(exONE()-power(t,exTWO()),exMINUSHALF());
565 return cosh(x).hold();
568 static ex cosh_diff(ex const & x, unsigned diff_param)
570 ASSERT(diff_param==0);
575 REGISTER_FUNCTION(cosh, cosh_eval, cosh_evalf, cosh_diff, NULL);
578 // hyperbolic tangent (trigonometric function)
581 static ex tanh_evalf(ex const & x)
585 END_TYPECHECK(tanh(x))
587 return tanh(ex_to_numeric(x)); // -> numeric tanh(numeric)
590 static ex tanh_eval(ex const & x)
592 if (x.info(info_flags::numeric)) {
596 // tanh(float) -> float
597 if (!x.info(info_flags::rational))
598 return tanh_evalf(x);
601 if (is_ex_exactly_of_type(x, function)) {
603 // tanh(atanh(x)) -> x
604 if (is_ex_the_function(x, atanh))
606 // tanh(asinh(x)) -> x*(1+x^2)^(-1/2)
607 if (is_ex_the_function(x, asinh))
608 return t*power(exONE()+power(t,exTWO()),exMINUSHALF());
609 // tanh(acosh(x)) -> (x-1)^(1/2)*(x+1)^(1/2)/x
610 if (is_ex_the_function(x, acosh))
611 return power(t-exONE(),exHALF())*power(t+exONE(),exHALF())*power(t,exMINUSONE());
614 return tanh(x).hold();
617 static ex tanh_diff(ex const & x, unsigned diff_param)
619 ASSERT(diff_param==0);
621 return exONE()-power(tanh(x),exTWO());
624 REGISTER_FUNCTION(tanh, tanh_eval, tanh_evalf, tanh_diff, NULL);
627 // inverse hyperbolic sine (trigonometric function)
630 static ex asinh_evalf(ex const & x)
634 END_TYPECHECK(asinh(x))
636 return asinh(ex_to_numeric(x)); // -> numeric asinh(numeric)
639 static ex asinh_eval(ex const & x)
641 if (x.info(info_flags::numeric)) {
645 // asinh(float) -> float
646 if (!x.info(info_flags::rational))
647 return asinh_evalf(x);
650 return asinh(x).hold();
653 static ex asinh_diff(ex const & x, unsigned diff_param)
655 ASSERT(diff_param==0);
657 return power(1+power(x,exTWO()),exMINUSHALF());
660 REGISTER_FUNCTION(asinh, asinh_eval, asinh_evalf, asinh_diff, NULL);
663 // inverse hyperbolic cosine (trigonometric function)
666 static ex acosh_evalf(ex const & x)
670 END_TYPECHECK(acosh(x))
672 return acosh(ex_to_numeric(x)); // -> numeric acosh(numeric)
675 static ex acosh_eval(ex const & x)
677 if (x.info(info_flags::numeric)) {
678 // acosh(0) -> Pi*I/2
680 return Pi*I*numeric(1,2);
682 if (x.is_equal(exONE()))
685 if (x.is_equal(exMINUSONE()))
687 // acosh(float) -> float
688 if (!x.info(info_flags::rational))
689 return acosh_evalf(x);
692 return acosh(x).hold();
695 static ex acosh_diff(ex const & x, unsigned diff_param)
697 ASSERT(diff_param==0);
699 return power(x-1,exMINUSHALF())*power(x+1,exMINUSHALF());
702 REGISTER_FUNCTION(acosh, acosh_eval, acosh_evalf, acosh_diff, NULL);
705 // inverse hyperbolic tangent (trigonometric function)
708 static ex atanh_evalf(ex const & x)
712 END_TYPECHECK(atanh(x))
714 return atanh(ex_to_numeric(x)); // -> numeric atanh(numeric)
717 static ex atanh_eval(ex const & x)
719 if (x.info(info_flags::numeric)) {
723 // atanh({+|-}1) -> throw
724 if (x.is_equal(exONE()) || x.is_equal(exONE()))
725 throw (std::domain_error("atanh_eval(): infinity"));
726 // atanh(float) -> float
727 if (!x.info(info_flags::rational))
728 return atanh_evalf(x);
731 return atanh(x).hold();
734 static ex atanh_diff(ex const & x, unsigned diff_param)
736 ASSERT(diff_param==0);
738 return power(exONE()-power(x,exTWO()),exMINUSONE());
741 REGISTER_FUNCTION(atanh, atanh_eval, atanh_evalf, atanh_diff, NULL);