Complex Number  0.1.2
src/ComplexMath.cpp
Go to the documentation of this file.
00001 // Copyright (c) 2010 Matthew Krupcale
00002 
00003 // Permission is hereby granted, free of charge, to any person
00004 // obtaining a copy of this software and associated documentation
00005 // files (the "Software"), to deal in the Software without
00006 // restriction, including without limitation the rights to use,
00007 // copy, modify, merge, publish, distribute, sublicense, and/or sell
00008 // copies of the Software, and to permit persons to whom the
00009 // Software is furnished to do so, subject to the following
00010 // conditions:
00011 
00012 // The above copyright notice and this permission notice shall be
00013 // included in all copies or substantial portions of the Software.
00014 
00015 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
00016 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
00017 // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
00018 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
00019 // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
00020 // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
00021 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
00022 // OTHER DEALINGS IN THE SOFTWARE.
00023 
00024 #ifndef COMPLEX_MATH_CPP
00025 #define COMPLEX_MATH_CPP
00026 
00027 //============================================================================
00028 // Name        : ComplexMath.cpp
00029 // Author      : Matthew Krupcale
00030 // Version     : 0.1.2
00031 // Copyright   : Copyright (C) 2010 Matthew Krupcale
00032 // Description : A set of mathematical functions for complex numbers
00033 //============================================================================
00034 
00046 #include "ComplexNumber.h"
00047 #include "ComplexMath.h"
00048 #include "MathExceptions.h"
00049 #include "Namespace.h"
00050 #include <cmath>
00051 #include <vector>
00052 
00060 BEGIN_NAMESPACE(math)
00061 
00062 
00069 BEGIN_NAMESPACE(complex)
00070 
00071 template <class T>
00072 T
00073 abs(const ComplexNumber<T>& z) {
00074     return std::sqrt(std::pow(z.getReal(), 2) +
00075                      std::pow(z.getImaginary(), 2));
00076 }
00077 
00078 template <class T>
00079 T
00080 abs2(const ComplexNumber<T>& z) {
00081     return std::pow(z.getReal(), 2) +
00082            std::pow(z.getImaginary(), 2);
00083 }
00084 
00085 template <class T>
00086 T
00087 arg(const ComplexNumber<T>& z) {
00088     if (z.getReal() == 0 && z.getImaginary() == 0) {
00089         return 0;
00090     }
00091     return std::atan2(z.getImaginary(), z.getReal());
00092 }
00093 
00094 template <class T>
00095 T
00096 logabs(const ComplexNumber<T>& z) {
00097     if (z == 0) {
00098         throw LogarithmOfZeroException();
00099     }
00100     return 0.5 * std::log(abs2(z));
00101 }
00102 
00103 template <class T>
00104 ComplexNumber<T>
00105 conjugate(const ComplexNumber<T>& z) {
00106     return ComplexNumber<T>(z.getReal(), -z.getImaginary());
00107 }
00108 
00109 template <class T>
00110 ComplexNumber<T>
00111 exp(const ComplexNumber<T>& z) {
00112     return ComplexNumber<T>(std::exp(z.getReal()) * std::cos(z.getImaginary()),
00113                             std::exp(z.getReal()) * std::sin(z.getImaginary()));
00114 }
00115 
00116 template <class T>
00117 ComplexNumber<T>
00118 inverse(const ComplexNumber<T>& z) {
00119     // prevent division by zero
00120     if (z == 0) {
00121         throw DivisionByZeroException();
00122     }
00123     return (conjugate(z) / abs2(z));
00124 }
00125 
00126 template <class T>
00127 ComplexNumber<T>
00128 log(const ComplexNumber<T>& z) {
00129     if (z == 0) {
00130         throw LogarithmOfZeroException();
00131     }
00132     return ComplexNumber<T>(logabs(z), arg(z));
00133 }
00134 
00135 template <class T>
00136 ComplexNumber<T>
00137 log(const T& x) {
00138     if (x == 0) {
00139         throw LogarithmOfZeroException();
00140     }
00141     return ComplexNumber<T>(std::log(std::abs(x)), std::atan2(0, x));
00142 }
00143 
00144 template <class T>
00145 ComplexNumber<T>
00146 log10(const ComplexNumber<T>& z) {
00147     return (log(z) / M_LN10l);
00148 }
00149 
00150 template <class T>
00151 ComplexNumber<T>
00152 log10(const T& x) {
00153     if (x == 0) {
00154         throw LogarithmOfZeroException();
00155     }
00156     return ComplexNumber<T>(std::log(std::abs(x)) / M_LN10l,
00157                             std::atan2(0, x) / M_LN10l);
00158 }
00159 
00160 template <class T>
00161 ComplexNumber<T>
00162 logb(const ComplexNumber<T>& z, const ComplexNumber<T>& b) {
00163     return (log(z) / log(b));
00164 }
00165 
00166 template <class T>
00167 ComplexNumber<T>
00168 logb(const ComplexNumber<T>& z, const T& b) {
00169     return (log(z) / log(b));
00170 }
00171 
00172 template <class T>
00173 ComplexNumber<T>
00174 logb(const T& x, const ComplexNumber<T>& b) {
00175     return (log(x) / log(b));
00176 }
00177 
00178 template <class T>
00179 ComplexNumber<T>
00180 logb(const T& x, const T& b) {
00181     return (log(x) / log(b));
00182 }
00183 
00184 template <class T>
00185 ComplexNumber<T>
00186 pow(const ComplexNumber<T>& a, const ComplexNumber<T>& b) {
00187     if (a == 0) {
00188         if (b == 0) {
00189             throw ZeroToTheZerothPowerException();
00190         } else {
00191             throw ZeroToComplexPowerException();
00192         }
00193     }
00194     return exp(b * log(a));
00195 }
00196 
00197 template <class T>
00198 ComplexNumber<T>
00199 pow(const ComplexNumber<T>& a, const T& b) {
00200     if (a == 0 && b ==0) {
00201         throw ZeroToTheZerothPowerException();
00202     }
00203     return exp(b * log(a));
00204 }
00205 
00206 template <class T>
00207 ComplexNumber<T>
00208 pow(const T& a, const ComplexNumber<T>& b) {
00209     if (a == 0) {
00210         if (b == 0) {
00211             throw ZeroToTheZerothPowerException();
00212         } else {
00213             throw ZeroToComplexPowerException();
00214         }
00215     }
00216     return exp(b * log(a));
00217 }
00218 
00219 template <class T>
00220 ComplexNumber<T>
00221 sqrt(const ComplexNumber<T>& z) {
00222     return ComplexNumber<T>(std::pow(std::pow(z.getReal(), 2) +
00223                                      std::pow(z.getImaginary(), 2), 0.25) *
00224                             std::cos(0.5 * arg(z)),
00225                             std::pow(std::pow(z.getReal(), 2) +
00226                                      std::pow(z.getImaginary(), 2), 0.25) *
00227                             std::sin(0.5 * arg(z)));
00228 }
00229 
00230 template <class T>
00231 ComplexNumber<T>
00232 sqrt(const T& x) {
00233     if (x >= 0) {
00234         return ComplexNumber<T>(std::sqrt(x), 0);
00235     } else {
00236         return ComplexNumber<T>(0, std::sqrt(-x));
00237     }
00238 }
00239 
00240 template <class T>
00241 ComplexNumber<T>
00242 cbrt(const ComplexNumber<T>& z) {
00243     return ComplexNumber<T>(std::pow(std::pow(z.getReal(), 2) +
00244                                      std::pow(z.getImaginary(), 2), 1. / 6) *
00245                             std::cos(arg(z) / 3),
00246                             std::pow(std::pow(z.getReal(), 2) +
00247                                      std::pow(z.getImaginary(), 2), 1. / 6) *
00248                             std::sin(arg(z) / 3));
00249 }
00250 
00251 template <class T>
00252 ComplexNumber<T>
00253 nthRoot(const ComplexNumber<T>& z, const int n) {
00254     if (n == 0) {
00255         throw DivisionByZeroException();
00256     }
00257     return ComplexNumber<T>(std::pow(std::pow(z.getReal(), 2) +
00258                                      std::pow(z.getImaginary(), 2), 1. / (2 * n)) *
00259                             std::cos(arg(z) / n),
00260                             std::pow(std::pow(z.getReal(), 2) +
00261                                      std::pow(z.getImaginary(), 2), 1. / (2 * n)) *
00262                             std::sin(arg(z) / n));
00263 }
00264 
00265 template <class T>
00266 std::vector<ComplexNumber<T> >
00267 nthRoots(const ComplexNumber<T>& z, const int n) {
00268     std::vector<ComplexNumber<T> > roots(n);
00269     nthRoots(z, roots, n);
00270     return roots;
00271 }
00272 
00273 template <class T>
00274 void
00275 nthRoots(const ComplexNumber<T>& z,
00276          std::vector<ComplexNumber<T> >& roots, const int n) {
00277     if (n == 0) {
00278         throw DivisionByZeroException();
00279     }
00280     int absN = (n < 0) ? -n : n;
00281     for (int i = 0; i < absN; i++) {
00282         roots.push_back(ComplexNumber<T>(std::pow(std::pow(z.getReal(), 2) +
00283                                                   std::pow(z.getImaginary(), 2), 1. / (2 * n)) *
00284                                          std::cos((arg(z) + 2 * i * M_PIl) / n),
00285                                          std::pow(std::pow(z.getReal(), 2) +
00286                                                   std::pow(z.getImaginary(), 2), 1. / (2 * n)) *
00287                                          std::sin((arg(z) + 2 * i * M_PIl) / n)));
00288     }
00289 }
00290 
00291 template <class T>
00292 ComplexNumber<T>
00293 sin(const ComplexNumber<T>& z) {
00294     return ComplexNumber<T>(std::sin(z.getReal()) * std::cosh(z.getImaginary()),
00295                             std::cos(z.getReal()) * std::sinh(z.getImaginary()));
00296 }
00297 
00298 template <class T>
00299 ComplexNumber<T>
00300 cos(const ComplexNumber<T>& z) {
00301     return ComplexNumber<T>(std::cos(z.getReal()) * std::cosh(z.getImaginary()),
00302                             -std::sin(z.getReal()) * std::sinh(z.getImaginary()));
00303 }
00304 
00305 template <class T>
00306 ComplexNumber<T>
00307 tan(const ComplexNumber<T>& z) {
00308     return ComplexNumber<T>(std::sin(2 * z.getReal()) /
00309                             (std::cosh(2 * z.getImaginary()) +
00310                              std::cos(2 * z.getReal())),
00311                             std::sinh(2 * z.getImaginary()) /
00312                             (std::cosh(2 * z.getImaginary()) +
00313                              std::cos(2 * z.getReal())));
00314 }
00315 
00316 template <class T>
00317 ComplexNumber<T>
00318 csc(const ComplexNumber<T>& z) {
00319     return inverse(sin(z));
00320 }
00321 
00322 template <class T>
00323 ComplexNumber<T>
00324 sec(const ComplexNumber<T>& z) {
00325     return inverse(cos(z));
00326 }
00327 
00328 template <class T>
00329 ComplexNumber<T>
00330 cot(const ComplexNumber<T>& z) {
00331     return inverse(cot(z));
00332 }
00333 
00334 template <class T>
00335 ComplexNumber<T>
00336 asin(const ComplexNumber<T>& z) {
00337     if (z.getImaginary() == 0) {
00338         return asin(z.getReal());
00339     } else {
00340         return -ComplexNumber<double>::i * log(ComplexNumber<double>::i * z +
00341                                                sqrt(1 - pow(z, 2)));
00342     }
00343 }
00344 
00345 template <class T>
00346 ComplexNumber<T>
00347 asin(const T& x) {
00348     if (std::abs(x) <= 1) {
00349         return ComplexNumber<T>(::asin(x), 0);
00350     } else {
00351         if (x < 0) {
00352             return ComplexNumber<T>(-M_PI_2l, ::acosh(-x));
00353         } else {
00354             return ComplexNumber<T>(M_PI_2l, -::acosh(x));
00355         }
00356     }
00357 }
00358 
00359 template <class T>
00360 ComplexNumber<T>
00361 acos(const ComplexNumber<T>& z) {
00362     if (z.getImaginary() == 0) {
00363         return acos(z.getReal());
00364     } else {
00365         return -ComplexNumber<double>::i * log(z + sqrt(pow(z, 2) - 1));
00366     }
00367 }
00368 
00369 template <class T>
00370 ComplexNumber<T>
00371 acos(const T& x) {
00372     if (std::abs(x) <= 1) {
00373         return ComplexNumber<T>(::acos(x), 0);
00374     } else {
00375         if (x < 0) {
00376             return ComplexNumber<T>(M_PIl, -::acosh(-x));
00377         } else {
00378             return ComplexNumber<T>(0, ::acosh(x));
00379         }
00380     }
00381 }
00382 
00383 template <class T>
00384 ComplexNumber<T>
00385 atan(const ComplexNumber<T>& z) {
00386     if (z.getImaginary() == 0) {
00387         return atan(z.getReal());
00388     } else {
00389         return ComplexNumber<double>::i * .5 * log((ComplexNumber<double>::i + z) /
00390                                                    (ComplexNumber<double>::i - z));
00391     }
00392 }
00393 
00394 template <class T>
00395 ComplexNumber<T>
00396 atan(const T& x) {
00397     return ComplexNumber<T>(std::atan(x), 0);
00398 }
00399 
00400 template <class T>
00401 ComplexNumber<T>
00402 acsc(const ComplexNumber<T>& z) {
00403     return asin(inverse(z));
00404 }
00405 
00406 template <class T>
00407 ComplexNumber<T>
00408 acsc(const T& x) {
00409     return asin(1. / x);
00410 }
00411 
00412 template <class T>
00413 ComplexNumber<T>
00414 asec(const ComplexNumber<T>& z) {
00415     return acos(inverse(z));
00416 }
00417 
00418 template <class T>
00419 ComplexNumber<T>
00420 asec(const T& x) {
00421     return acos(1. / x);
00422 }
00423 
00424 template <class T>
00425 ComplexNumber<T>
00426 acot(const ComplexNumber<T>& z) {
00427     return atan(inverse(z));
00428 }
00429 
00430 template <class T>
00431 ComplexNumber<T>
00432 acot(const T& x) {
00433     return atan(1. / x);
00434 }
00435 
00436 template <class T>
00437 ComplexNumber<T>
00438 sinh(const ComplexNumber<T>& z) {
00439     return ComplexNumber<T>(std::sinh(z.getReal()) * std::cos(z.getImaginary()),
00440                             std::cosh(z.getReal()) * std::sin(z.getImaginary()));
00441 }
00442 
00443 template <class T>
00444 ComplexNumber<T>
00445 cosh(const ComplexNumber<T>& z) {
00446     return ComplexNumber<T>(std::cosh(z.getReal()) * std::cos(z.getImaginary()),
00447                             std::sinh(z.getReal()) * std::sin(z.getImaginary()));
00448 }
00449 
00450 template <class T>
00451 ComplexNumber<T>
00452 tanh(const ComplexNumber<T>& z) {
00453     return ComplexNumber<T>(std::sinh(2 * z.getReal()) /
00454                             (std::cos(2 * z.getImaginary()) +
00455                              std::cosh(2 * z.getReal())),
00456                             std::sin(2 * z.getImaginary()) /
00457                             (std::cos(2 * z.getImaginary()) +
00458                              std::cosh(2 * z.getReal())));
00459 }
00460 
00461 template <class T>
00462 ComplexNumber<T>
00463 csch(const ComplexNumber<T>& z) {
00464     return inverse(sinh(z));
00465 }
00466 
00467 template <class T>
00468 ComplexNumber<T>
00469 sech(const ComplexNumber<T>& z) {
00470     return inverse(cosh(z));
00471 }
00472 
00473 template <class T>
00474 ComplexNumber<T>
00475 coth(const ComplexNumber<T>& z) {
00476     return inverse(tanh(z));
00477 }
00478 
00479 template <class T>
00480 ComplexNumber<T>
00481 asinh(const ComplexNumber<T>& z) {
00482     if (z.getImaginary() == 0) {
00483         return asinh(z.getReal());
00484     } else {
00485         return log(z + sqrt(pow(z, 2) + 1));
00486     }
00487 }
00488 
00489 template <class T>
00490 ComplexNumber<T>
00491 asinh(const T& x) {
00492     return ComplexNumber<T>(::asinh(x), 0);
00493 }
00494 
00495 template <class T>
00496 ComplexNumber<T>
00497 acosh(const ComplexNumber<T>& z) {
00498     if (z.getImaginary() == 0) {
00499         return acosh(z.getReal());
00500     } else {
00501         return log(z + sqrt(z - 1) * sqrt(z + 1));
00502     }
00503 }
00504 
00505 template <class T>
00506 ComplexNumber<T>
00507 acosh(const T& x) {
00508     if (x >= 1) {
00509         return ComplexNumber<T>(::acosh(x), 0);
00510     } else {
00511         if (x >= -1) {
00512             return ComplexNumber<T>(0, ::acos(x));
00513         } else {
00514             return ComplexNumber<T>(::acosh(-x), M_PIl);
00515         }
00516     }
00517 }
00518 
00519 template <class T>
00520 ComplexNumber<T>
00521 atanh(const ComplexNumber<T>& z) {
00522     if (z.getImaginary() == 0) {
00523         return atanh(z.getReal());
00524     } else {
00525         return 0.5 * log((1 + z) / (1 - z));
00526     }
00527 }
00528 
00529 template <class T>
00530 ComplexNumber<T>
00531 atanh(const T& x) {
00532     if (std::abs(x) < 1) {
00533         return ComplexNumber<T>(::atanh(x), 0);
00534     } else {
00535         return ComplexNumber<T>(::atanh(1. / x), (x < 0) ? M_PI_2l : -M_PI_2l);
00536     }
00537 }
00538 
00539 template <class T>
00540 ComplexNumber<T>
00541 acsch(const ComplexNumber<T>& z) {
00542     return asinh(inverse(z));
00543 }
00544 
00545 template <class T>
00546 ComplexNumber<T>
00547 acsch(const T& x) {
00548     return ComplexNumber<T>(::asinh(1. / x), 0);
00549 }
00550 
00551 template <class T>
00552 ComplexNumber<T>
00553 asech(const ComplexNumber<T>& z) {
00554     return acosh(inverse(z));
00555 }
00556 
00557 template <class T>
00558 ComplexNumber<T>
00559 asech(const T& x) {
00560     if (x > 0 && x <= 1) {
00561         return ComplexNumber<T>(::acosh(1. / x), 0);
00562     } else {
00563         return acosh(1. / x);
00564     }
00565 }
00566 
00567 template <class T>
00568 ComplexNumber<T>
00569 acoth(const ComplexNumber<T>& z) {
00570     return atanh(inverse(z));
00571 }
00572 
00573 template <class T>
00574 ComplexNumber<T>
00575 acoth(const T& x) {
00576     if (std::abs(x) > 1) {
00577         return ComplexNumber<T>(::atanh(1. / x), 0);
00578     } else {
00579         return atanh(1. / x);
00580     }
00581 }
00582 
00583 END_NAMESPACE(complex)
00584 END_NAMESPACE(math)
00585 
00586 #endif /* COMPLEX_MATH_CPP */