Complex Number 0.1.2 |
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 */