/****************************************** * C++ Complex Numbers * Version: 1.0.9 * Author: Douglas Wilhelm Harder * Date: 2008/03/03 * * Copyright (c) 2006-2008 by Douglas Wilhelm Harder. * All rights reserved. * * Acknowledgments: * Andre Kostro ******************************************/ #include "Complex.h" #include "Support.h" #include #include #include template inline char Complex::use_symbol( char sym ) { char tmp = imaginary_symbol; imaginary_symbol = sym; return tmp; } template inline char Complex::get_symbol() { return imaginary_symbol; } /****************************************** * Constructors ******************************************/ // (a, b) -> a + bi template Complex::Complex( T re, T im ):r(re), i(im) { // empty } template Complex::Complex( T re ):r(re), i(0.0) { // empty } /****************************************** * Assignment Operator ******************************************/ // z = 3 -> z == 3 + 0i template inline const Complex & Complex::operator = ( T x ) { r = x; i = 0.0; return *this; } /****************************************** * Mutating Arithmetic Operators ******************************************/ // (a + bi) + (c + di) = (a + c) + (b + d)i template inline Complex & Complex::operator += ( const Complex & z ) { r += z.r; i += z.i; return *this; } // (a + bi) + x = (a + c) + bi template inline Complex & Complex::operator += ( T x ) { r += x; return *this; } // (a + bi) - (c + di) = (a - c) + (b - d)i template inline Complex & Complex::operator -= ( const Complex & z ) { r -= z.r; i -= z.i; return *this; } // (a + bi) - x = (a - x) + bi template inline Complex & Complex::operator -= ( T x ) { r -= x; return *this; } // (a + bi) * (c + di) = (a*c - b*d) + (a*c + b*d)i template inline Complex & Complex::operator *= ( const Complex & z ) { T RE = r; r = r * z.r - i * z.i; i = RE * z.i + z.r * i; return *this; } // if ( x != oo ) // (a + bi) * x = ax + bxi // else // (a + 0i) * oo = oo + 0i // (0 + bi) * oo = 0 + ooi // (0 + 0i) * oo = NaN + NaNi template inline Complex & Complex::operator *= ( T x ) { if ( Support::is_inf( x ) && !is_zero() ) { r *= ( r == 0.0 ) ? Support::sign( x ) : x; i *= ( i == 0.0 ) ? Support::sign( x ) : x; } else { r *= x; i *= x; } return * this; } // n = c^2 + d^2 // (a + bi) / (c + di) = (a*c + b*d)/n + ((a*c - b*d)/n)i template inline Complex & Complex::operator /= ( const Complex & z ) { T denom = z.norm(); T RE = r; r = ( RE*z.r + i * z.i)/denom; i = (-RE*z.i + z.r * i)/denom; return * this; } // if ( x != 0 ) // (a + bi) / x = (a/x) + (b/x)i // else // (a + 0i) / 0 = oo + 0i // (0 + bi) / 0 = 0 + ooi // (0 + 0i) / 0 = NaN + NaNi template inline Complex & Complex::operator /= ( T x ) { if ( ( x == 0.0 ) && !is_zero() ) { r /= ( r == 0.0 ) ? Support::sign( x ) : x; i /= ( i == 0.0 ) ? Support::sign( x ) : x; } else { r /= x; i /= x; } return * this; } // ++(a + bi) = (a + 1) + bi // Returns (a + 1) + bi template inline Complex & Complex::operator ++() { ++r; return *this; } // (a + bi)++ = (a + 1) + bi // Returns a + bi template inline Complex Complex::operator ++( int ) { Complex copy = *this; ++r; return copy; } // --(a + bi) = (a - 1) + bi // Returns (a - 1) + bi template inline Complex & Complex::operator --() { --r; return *this; } // (a + bi)-- = (a - 1) + bi // Returns a + bi template inline Complex Complex::operator --( int ) { Complex copy = *this; --r; return copy; } /****************************************** * Real-valued Functions ******************************************/ template inline T Complex::real() const { return r; } template inline T Complex::operator []( int n ) const { return reinterpret_cast( this )[n]; } template inline T & Complex::operator []( int n ) { return reinterpret_cast( this )[n]; } template inline T Complex::imag_i() const { return i; } template inline T Complex::csgn() const { return is_zero() ? 0 : Support::sign( r ); } // if a != oo && b != oo // (a + bi) -> sqrt( a^2 + b^2 ) // else // ( a + ooi) -> oo // (oo + bi) -> oo // (oo + ooi) -> oo template inline T Complex::abs() const { return is_inf()? Support::POS_INF : std::sqrt( r*r + i*i ); } // if a != oo && b != oo // (a + bi) -> a^2 + b^2 // else // ( a + ooi) -> oo // (oo + bi) -> oo // (oo + ooi) -> oo template inline T Complex::norm() const { return is_inf() ? Support::POS_INF : r*r + i*i; } // a + bi -> |b| template inline T Complex::abs_imag() const { return ( i >= 0.0 ) ? i : -i; } // a + bi -> b^2 template inline T Complex::norm_imag() const { return i*i; } // (a + bi) -> arctan( b, a ) template inline T Complex::arg() const { return std::atan2( i, r ); } /****************************************** * Complex-valued Functions ******************************************/ // (a + bi) -> (0 + bi) template inline Complex Complex::imag() const { return Complex( 0.0, i ); } // (a + bi) -> (a - bi) template inline Complex Complex::conj() const { return Complex( r, -i ); } template inline Complex Complex::operator * () const { return Complex( r, -i ); } template inline Complex Complex::signum() const { T absq = abs(); if ( absq == 0.0 || Support::is_nan( absq ) || Support::is_inf( absq ) ) { return *this; } else { return Complex( r/absq, i/absq ); } } // (a + bi)^2 = (a^2 - b^2) + 2abi template inline Complex Complex::sqr() const { return Complex( r*r - i*i, 2*r*i ); } // Branch cut: (-oo, 0) // Thanks: Chris Saunders template inline Complex Complex::sqrt() const { T srss = std::sqrt( r*r + i*i ); return Complex( 0.5*std::sqrt( 2*(srss + r) ), 0.5*Complex( i, -r ).csgn()*std::sqrt( 2*( srss - r ) ) ); } /****************************************** * Boolean-valued Functions ******************************************/ // (0 + bi) -> true // false otherwise template inline bool Complex::is_imaginary() const { return ( r == 0.0 ); } // if a == +/-oo || b == +/- oo // (a + bi) -> true // false otherwise template inline bool Complex::is_inf() const { return ( r == Support::POS_INF ) || ( r == Support::NEG_INF ) || ( i == Support::POS_INF ) || ( i == Support::NEG_INF ); } // if a == NaN or b == NaN // (a + bi) -> true // false otherwise template inline bool Complex::is_nan() const { return ( r != r ) || ( i != i ); } // -oo + 0i -> true template inline bool Complex::is_neg_inf() const { return ( r == Support::NEG_INF ) && i == 0.0; } // oo + 0i -> true template inline bool Complex::is_pos_inf() const { return ( r == Support::POS_INF ) && ( i == 0.0 ); } // +/-oo + 0i -> true template inline bool Complex::is_real_inf() const { return ( r == Support::POS_INF || r == Support::NEG_INF ) && i == 0.0; } // a + 0i -> true template inline bool Complex::is_real() const { return ( i == 0.0 ); } // 0 + 0i -> true template inline bool Complex::is_zero() const { return ( r == 0.0 ) && ( i == 0.0 ); } /****************************************** * Exponential and Logarithmic Functions ******************************************/ /****************************************** * Exponential Function * * Checked for errors. ******************************************/ template inline Complex Complex::exp() const { if ( i == 0.0 ) { return Complex( std::exp( r ), i ); } else if ( r == 0.0 ) { return Complex( std::cos( i ), std::sin( i ) ); } else { T expr = std::exp( r ); return Complex( expr * std::cos( i ), expr * std::sin( i ) ); } } /****************************************** * Logarithmic Function * * Checked for errors. ******************************************/ template inline Complex Complex::log() const { if ( i == 0 ) { if ( r > 0 ) { return Complex( std::log( r ), i ); } else if ( r == 0 ) { return Complex( Support::NEG_INF, Support::NaN ); } else { return Complex( std::log( -r ), Support::sign( i )*Support::PI ); } } else if ( r == 0 ) { if ( i > 0 ) { return Complex( std::log( i ), Support::PI2 ); } else { return Complex( std::log( -i ), -Support::PI2 ); } } else { return Complex( 0.5 * std::log( r*r + i*i ), std::atan2( i, r ) ); } } // Branch cut: (-oo, 0] template inline Complex Complex::log10() const { { T ln10 = std::log( 10.0 ); return Complex( 0.5 * std::log( r*r + i*i ) / ln10, std::atan2( i, r ) / ln10 ); } } // (a + bi)^(c + di) -> exp( log(a + bi)*(c + di) ) template inline Complex Complex::pow( const Complex & z ) const { if ( is_zero() && z.is_zero() ) { return Complex( Support::NaN, Support::NaN ); } else if ( is_zero() ) { if ( Support::sign( r ) == 1 ) { return Complex( 0.0, 0.0 ); } else { return Complex( Support::POS_INF, Support::POS_INF ); } } else if ( z.is_zero() ) { return Complex( 1.0, 0.0 ); } if ( i == 0 ) { if ( z.i == 0 ) { if ( r > 0 ) { return Complex( std::pow( r, z.r ), 0.0 ); } else { std::cout << "B" << std::endl; return Complex( std::exp(z.r*std::log(-r))*std::cos(z.r*Support::PI), -std::exp(z.r*std::log(-r))*std::sin(z.r*Support::PI) ); } } else if ( z.r == 0 ) { if ( r > 0 ) { return Complex( std::cos( z.i*std::log( r ) ), std::sin( z.i*std::log( r ) ) ); } else { std::cout << "D" << std::endl; if ( Support::sign( i ) == 1 ) { return Complex( std::exp( -z.i*Support::PI )*std::cos( z.i*std::log( -r ) ), std::exp( -z.i*Support::PI )*std::sin( z.i*std::log( -r ) ) ); } else { return Complex( std::exp( z.i*Support::PI )*std::cos( z.i*std::log( -r ) ), std::exp( z.i*Support::PI )*std::sin( z.i*std::log( -r ) ) ); } } } else { if ( r > 0 ) { return Complex( std::exp( z.r*std::log(r) )*std::cos( z.i*std::log(r)), std::exp( z.r*std::log(r) )*std::sin( z.i*std::log(r) ) ); } else { if ( Support::sign( i ) == 1 ) { return Complex( std::exp( z.r*std::log(-r) - z.i*Support::PI )* std::cos( z.i*std::log(-r) + z.r*Support::PI ), std::exp( z.r*std::log(-r) - z.i*Support::PI )* std::sin( z.i*std::log(-r) + z.r*Support::PI ) ); } else { return Complex( std::pow( -r, z.r )* std::exp(z.i*Support::PI)*std::cos(-z.i*std::log(-r) + z.r*Support::PI), -std::pow( -r, z.r )* std::exp(z.i*Support::PI)*std::sin(-z.i*std::log(-r) + z.r*Support::PI) ); } } } } else if ( r == 0 ) { if ( z.i == 0 ) { return Complex( std::exp(0.5*z.r*std::log(i*i))*std::cos(0.5*z.r*Support::sign(i)*Support::PI), std::exp(0.5*z.r*std::log(i*i))*std::sin(0.5*z.r*Support::sign(i)*Support::PI) ); } else if ( z.r == 0 ) { return Complex( std::exp(-0.5*z.i*Support::sign(i)*Support::PI)*std::cos(0.5*z.i*std::log(i*i)), std::exp(-0.5*z.i*Support::sign(i)*Support::PI)*std::sin(0.5*z.i*std::log(i*i)) ); } else { return Complex( std::exp(0.5*z.r*std::log(i*i) - 0.5*z.i*Support::sign(i)*Support::PI)*std::cos(0.5*z.i*std::log(i*i) + 0.5*z.r*Support::sign(i)*Support::PI), std::exp(0.5*z.r*std::log(i*i) - 0.5*z.i*Support::sign(i)*Support::PI)*std::sin(0.5*z.i*std::log(i*i) + 0.5*z.r*Support::sign(i)*Support::PI) ); } } else { if ( z.i == 0 ) { return Complex( std::exp(0.5*z.r*std::log(r*r + i*i))*std::cos(z.r*std::atan2(i,r)), std::exp(0.5*z.r*std::log(r*r + i*i))*std::sin(z.r*std::atan2(i,r)) ); } else if ( z.r == 0 ) { return Complex( std::exp(-z.i*std::atan2(i,r))*std::cos(0.5*z.i*std::log(r*r + i*i)), std::exp(-z.i*std::atan2(i,r))*std::sin(0.5*z.i*std::log(r*r + i*i)) ); } else { return Complex( std::exp(0.5*z.r*std::log(r*r + i*i)-z.i*std::atan2(i,r))*std::cos(0.5*z.i*std::log(r*r + i*i) + z.r*std::atan2(i,r)), std::exp(0.5*z.r*std::log(r*r + i*i)-z.i*std::atan2(i,r))*std::sin(0.5*z.i*std::log(r*r + i*i) + z.r*std::atan2(i,r)) ); } } } template inline Complex Complex::pow(T x) const { if ( i == 0 ) { return Complex( std::exp( x*std::log( std::fabs(r) ) )*std::cos( x*(0.5 - 0.5*Support::sign(r) )*Support::PI ), std::exp( x*std::log( std::fabs(r) ) )*std::sin( x*(0.5 - 0.5*Support::sign(r) )*Support::PI ) ); } else if ( r == 0 ) { return Complex( std::exp( 0.5*x*std::log( i*i ) )*std::cos( 0.5*x*Support::sign(i)*Support::PI ), std::exp( 0.5*x*std::log( i*i ) )*std::sin( 0.5*x*Support::sign(i)*Support::PI ) ); } else { return Complex( std::exp( 0.5*x*std::log( r*r + i*i ) )*std::cos( x*std::atan2( i, r ) ), std::exp( 0.5*x*std::log( r*r + i*i ) )*std::sin( x*std::atan2( i, r ) ) ); } } template inline Complex Complex::inverse() const { if ( is_zero() ) { return Complex( Support::sign( r )*Support::POS_INF, -Support::sign( i )*Support::POS_INF ); } else if ( is_inf() ) { return Complex( Support::sign( r )*0.0, -Support::sign( i )*0.0 ); } else if ( is_nan() ) { return Complex( Support::NaN, Support::NaN ); } else { T denom = norm(); return Complex( r/denom, -i/denom ); } } /****************************************** * Trigonometric and Hyperbolic Functions ******************************************/ // a + 0i -> sin(a) + 0i // 0 + bi -> 0 + sinh(b)i // a + bi -> [sin(a) cosh(b)] + [cos(a) sinh(b)]i template inline Complex Complex::sin() const { if ( i == 0.0 ) { return Complex( std::sin( r ), std::cos( r )*i ); } else if ( r == 0.0 ) { return Complex( r, std::sinh( i ) ); } else { return Complex( std::sin( r ) * std::cosh( i ), std::cos( r ) * std::sinh( i ) ); } } /****************************************** * Cosine Function * * a + 0i -> cos(a) + 0i * 0 + bi -> 0 + cosh(b)i * a + bi -> [cos(a) cosh(b)] - [sin(a) sinh(b)]i * * Checked for errors. ******************************************/ template inline Complex Complex::cos() const { if ( i == 0.0 ) { return Complex( std::cos( r ), -i*std::sin( r ) ); } else if ( r == 0.0 ) { return Complex( std::cosh( i ), -i*r ); } else { return Complex( std::cos( r ) * std::cosh( i ), -std::sin( r ) * std::sinh( i ) ); } } template inline Complex Complex::tan() const { if ( i == 0.0 ) { return Complex( std::tan( r ), i ); } else if ( r == 0.0 ) { return Complex( r, std::tanh( i ) ); } else { T cosr = std::cos(r); T sinhi = std::sinh(i); T denom = cosr*cosr + sinhi*sinhi; return Complex( std::sin( r ) * cosr / denom, sinhi * std::cosh( i ) / denom ); } } template inline Complex Complex::sec() const { if ( i == 0.0 ) { return Complex( Support::sec( r ), -i ); } else if ( r == 0.0 ) { return Complex( Support::sech( i ), r*Support::sign( i ) ); } else { T cosr = std::cos(r); T sinhi = std::sinh(i); T denom = cosr*cosr + sinhi*sinhi; return Complex( cosr * std::cosh( i ) / denom, std::sin( r ) * sinhi / denom ); } } template inline Complex Complex::csc() const { if ( i == 0.0 ) { return Complex( Support::csc( r ), -i ); } else if ( r == 0.0 ) { return Complex( r, -Support::csch( i ) ); } else { T sinr = std::sin(r); T sinhi = std::sinh(i); T denom = sinr*sinr + sinhi*sinhi; return Complex( sinr * std::cosh( i ) / denom, -std::cos( r ) * sinhi / denom ); } } template inline Complex Complex::cot() const { if ( i == 0.0 ) { return Complex( Support::cot( r ), i ); } else if ( r == 0.0 ) { return Complex( r, -Support::coth( i ) ); } else { T sinr = std::sin(r); T sinhi = std::sinh(i); T denom = sinr*sinr + sinhi*sinhi; return Complex( sinr * std::cos( r ) / denom, -sinhi * std::cosh( i ) / denom ); } } // a + 0i -> sinh(a) + 0i // 0 + bi -> 0 + sin(b)i // a + bi -> [sinh(a) cos(b)] + [cosh(a) sin(b)]i template inline Complex Complex::sinh() const { if ( i == 0.0 ) { return Complex( std::sinh( r ), i ); } else if ( r == 0.0 ) { return Complex( r, std::sin( i ) ); } else { return Complex( std::sinh( r ) * std::cos( i ), std::cosh( r ) * std::sin( i ) ); } } // a + 0i -> cosh(a) + 0i // 0 + bi -> cos(b) + 0i // a + bi -> [cosh(a) cos(b)] + [sinh(a) sin(b)]i template inline Complex Complex::cosh() const { if ( i == 0.0 ) { return Complex( std::cosh( r ), i ); } else if ( r == 0.0 ) { return Complex( std::cos( i ), -r ); } else { return Complex( std::cosh( r ) * std::cos( i ), std::sinh( r ) * std::sin( i ) ); } } template inline Complex Complex::tanh() const { if ( i == 0.0 ) { return Complex( std::tanh( r ), i ); } else if ( r == 0.0 ) { return Complex( r, std::tan( i ) ); } else { T sinhr = std::sinh(r); T cosi = std::cos(i); T denom = sinhr*sinhr + cosi*cosi; return Complex( sinhr * std::cosh( r ) / denom, std::sin( i ) * cosi / denom ); } } template inline Complex Complex::sech() const { if ( i == 0.0 ) { return Complex( Support::sech( r ), -i ); } else if ( r == 0.0 ) { return Complex( Support::sec( i ), r ); } else { T sinhr = std::sinh(r); T cosi = std::cos(i); T denom = sinhr*sinhr + cosi*cosi; return Complex( std::cosh( r ) * cosi / denom, -sinhr * std::sin( i ) / denom ); } } template inline Complex Complex::csch() const { if ( i == 0.0 ) { return Complex( Support::csch( r ), -i ); } else if ( r == 0.0 ) { return Complex( r, -Support::csc( i ) ); } else { T sinhr = std::sinh(r); T sini = std::sin(i); T denom = sinhr*sinhr + sini*sini; return Complex( sinhr * std::cos( i ) / denom, -std::cosh( r ) * sini / denom ); } } template inline Complex Complex::coth() const { if ( i == 0.0 ) { return Complex( Support::coth( r ), i ); } else if ( r == 0.0 ) { return Complex( r, -Support::cot( i ) ); } else { T sinhr = std::sinh(r); T sini = std::sin(i); T denom = sinhr*sinhr + sini*sini; return Complex( sinhr * std::cosh( r ) / denom, -std::cos( i ) * sini / denom ); } } // Branch cut: (-oo, -1) U (1, oo) template inline Complex Complex::asin() const { if ( i == 0 ) { if ( r >= -1 && r <= 1 ) { return Complex( std::asin( r ), i ); } else { if ( r > 1 ) { return Complex( Support::PI2, Support::sign( i )*std::log( r + std::sqrt(r*r - 1) ) ); } else { return Complex( -Support::PI2, Support::sign( i )*std::log( -r + std::sqrt(r*r - 1) ) ); } } } else if ( r == 0 ) { return Complex( r, std::log( i + std::sqrt( i*i + 1 ) ) ); } else { T ss = r*r + i*i + 1; T ssp2r = std::sqrt( ss + 2*r ); T ssm2r = std::sqrt( ss - 2*r ); T sum = 0.5*( ssp2r + ssm2r ); return Complex( std::asin( ssp2r/2 - ssm2r/2 ), Complex( i, -r ).csgn()*std::log( sum + std::sqrt(sum*sum - 1) ) ); } } // Branch cut: (-oo, -1) U (1, oo) template inline Complex Complex::acos() const { if ( i == 0 ) { if ( r >= -1 && r <= 1 ) { return Complex( std::acos( r ), -i ); } else if ( r > 1 ) { return Complex( 0.0, -Support::sign( i )*std::log( r + std::sqrt(r*r - 1) ) ); } else { return Complex( Support::PI, -Support::sign( i )*std::log( -r + std::sqrt(r*r - 1) ) ); } } else { T ss = r*r + i*i + 1; T ssp2r = std::sqrt( ss + 2*r ); T ssm2r = std::sqrt( ss - 2*r ); T sum = 0.5*( ssp2r + ssm2r ); return Complex( std::acos( 0.5*(ssp2r - ssm2r) ), -Complex( i, -r ).csgn()*std::log( sum + std::sqrt(sum*sum - 1) ) ); } } /********************************************************** * Arc Tangent Function * * Branch cut: (-ooi, -i] U [i, ooi) * * There do not appear to be any errors in this function * for finite arguments. * Should simplify for r == 0, however. **********************************************************/ template inline Complex Complex::atan() const { if ( r == 0 ) { if ( i < -1 ) { T ip = i + 1; T im = i - 1; return Complex( Support::sign(r)*Support::PI2, 0.25*std::log( ip*ip/(im*im) ) ); } else if ( i == -1 ) { return Complex( Support::NaN, Support::NEG_INF ); } else if ( i == 0 ) { return *this; } else if ( i < 1 ) { T ip = i + 1; T im = i - 1; return Complex( r, 0.25*std::log( ip*Support::PI/(im*im) ) ); } else if ( i == 1 ) { return Complex( Support::NaN, Support::POS_INF ); } else { T ip = i + 1; T im = i - 1; return Complex( Support::sign(r)*Support::PI2, 0.25*std::log( ip*ip/(im*im) ) ); } } else if ( i == 0 ) { return Complex( std::atan( r ), i ); } else { T opi = 1.0 + i; T omi = 1.0 - i; T rr = r*r; return Complex( 0.5*( std::atan2( r, omi ) - std::atan2( -r, opi ) ), 0.25*std::log( (rr + opi*opi)/(rr + omi*omi) ) ); } } /********************************************************** * Arc Secant Function * * Branch cut: (-1, 1) * * There do not appear to be any errors in this function * for finite arguments. **********************************************************/ template inline Complex Complex::asec() const { if ( i == 0 ) { if ( ( r <= -1 ) || ( r >= 1 ) ) { return Complex( std::acos( 1/r ), i ); } else if ( r == 0 ) { return Complex( Support::POS_INF, Support::POS_INF ); } else { if ( r < 0 ) { return Complex( Support::PI, Support::sign( i )*std::log( -1/r + std::sqrt(1/(r*r) - 1) ) ); } else { return Complex( 0.0, Support::sign( i )*std::log( 1/r + std::sqrt(1/(r*r) - 1) ) ); } } } else { T ss = r*r + i*i; T p1 = r/ss; T p1p1 = p1 + 1; p1p1 = p1p1 * p1p1; T p1m1 = p1 - 1; p1m1 = p1m1 * p1m1; T p2 = i/ss; p2 = p2*p2; T p1p1p2 = std::sqrt( p1p1 + p2 ); T p1m1p2 = std::sqrt( p1m1 + p2 ); T sum = 0.5*( p1p1p2 + p1m1p2 ); return Complex( std::acos( 0.5*(p1p1p2 - p1m1p2 ) ), Complex( i, r ).csgn()*std::log( sum + std::sqrt(sum*sum - 1) ) ); } } /********************************************************** * Arc Cosecant Function * * Branch cut: (-1, 1) * * There do not appear to be any errors in this function * for finite arguments. **********************************************************/ template inline Complex Complex::acsc() const { if ( i == 0 ) { if ( ( r <= -1 ) || ( r >= 1 ) ) { // (-inf, 1] U [1, inf) return Complex( std::asin( 1/r ), -i ); } else if ( r == 0 ) { // 0 return Complex( Support::POS_INF, Support::POS_INF ); } else if ( r < 0 ) { // (-1, 0) return Complex( -Support::PI2, -Support::sign( i )*std::log( -1/r + std::sqrt(1/(r*r) - 1) ) ); } else { // (0, 1) return Complex( Support::PI2, -Support::sign( i )*std::log( 1/r + std::sqrt(1/(r*r) - 1) ) ); } } else if ( r == 0 ) { return Complex( r, -std::log( 1/i + std::sqrt( 1 + 1/(i*i) ) ) ); } else { T ss = r*r + i*i; T p1 = r/ss; T p1p1 = p1 + 1; p1p1 = p1p1 * p1p1; T p1m1 = p1 - 1; p1m1 = p1m1 * p1m1; T p2 = i/ss; p2 = p2*p2; T p1p1p2 = std::sqrt( p1p1 + p2 ); T p1m1p2 = std::sqrt( p1m1 + p2 ); T sum = 0.5*( p1p1p2 + p1m1p2 ); return Complex( std::asin( 0.5*(p1p1p2 - p1m1p2) ), -Complex( i, r ).csgn()*std::log( sum + std::sqrt(sum*sum - 1) ) ); } } // Branch cut: (-i, i) template inline Complex Complex::acot() const { if ( i == 0 ) { return Complex( Support::PI2 - std::atan( r ), -i ); } else if ( r == 0 ) { if ( i < -1 ) { // (-inf i, -i) return Complex( Support::sign( r ) == 1 ? 0.0 : Support::PI, 0.5*std::log( (-i + 1)/(-i - 1) ) ); } else if ( i == -1 ) { return Complex( Support::NaN, Support::POS_INF ); } else if ( i < 1 ) { // (-i, i) return Complex( Support::PI2, -0.25*std::log( (i + 1)*(i + 1)/((i - 1)*(i - 1)) ) ); } else if ( i == 1 ) { return Complex( Support::NaN, Support::NEG_INF ); } else { // (i, inf i) return Complex( Support::sign( r ) == 1 ? 0.0 : Support::PI, 0.5*std::log( (-i + 1)/(-i - 1) ) ); } } else { T opi = 1.0 + i; T omi = 1.0 - i; T rr = r*r; return Complex( Support::PI2 + 0.5*( std::atan2( -r, opi ) - std::atan2( r, omi ) ), -0.25*std::log( (rr + opi*opi)/(rr + omi*omi) ) ); } } /********************************************************** * Arc Hyperbolic Sine Function * * Branch cut: (-ooi, -i) U (i, ooi) * * There do not appear to be any errors in this function * for finite arguments. **********************************************************/ template inline Complex Complex::asinh() const { if ( r == 0 ) { if ( ( i >= -1 ) && ( i <= 1 ) ) { // [-i, i] return Complex( r, std::asin( i ) ); } else if ( i > 1 ) { // (i, ooi) return Complex( Support::sign( r )*std::log( i + std::sqrt( i*i - 1 ) ), Support::PI2 ); } else { // (-ooi, -i) return Complex( Support::sign( r )*std::log( -i + std::sqrt( i*i - 1 ) ), -Support::PI2 ); } } else if ( i == 0 ) { return Complex( std::log( r + std::sqrt( r*r + 1 ) ), i ); } else { T ss = r*r + i*i + 1; T ssp2i = std::sqrt( ss + 2*i ); T ssm2i = std::sqrt( ss - 2*i ); T sum = 0.5*( ssp2i + ssm2i ); return Complex( Complex( r, i ).csgn()*std::log( sum + std::sqrt(sum*sum - 1) ), std::asin( ssp2i/2 - ssm2i/2 ) ); } } // Branch cut: (-oo, 1) template inline Complex Complex::acosh() const { if ( i == 0 ) { if ( r > 1 ) { // (1, oo) return Complex( std::log( r + std::sqrt( (r - 1)*(r + 1) ) ), i ); } else if ( r == 1 ) { // 1 return Complex( 0.0, i ); } else if ( r == 0 ) { // 0 return Complex( 0.0, Support::sign( i )*Support::PI2 ); } else if ( r > -1 ) { // (-1, 0) U (0, 1) return Complex( 0.0, Support::sign( i )*std::acos( r ) ); } else if ( r == -1 ) { // -1 return Complex( 0.0, Support::sign( i )*Support::PI ); } else { // (-oo, -1) return Complex( std::log( -r + std::sqrt( (-1 - r)*(1 - r) ) ), Support::sign( i )*Support::PI ); } } else if ( r == 0 ) { return Complex( std::log( std::sqrt( i*i + 1 ) + Support::sign( i )*i ), Support::sign( i )*Support::PI2 ); } else { T ss = r*r + i*i + 1; T ssp2r = std::sqrt( ss + 2*r ); T ssm2r = std::sqrt( ss - 2*r ); T sum = 0.5*( ssp2r + ssm2r ); return Complex( Complex( -i, r - 1.0 ).csgn()* Complex( -i, r ).csgn()*std::log( sum + std::sqrt(sum*sum - 1) ), -Complex( -i, r - 1.0 ).csgn()*std::acos( ssp2r/2 - ssm2r/2 ) ); } } // Branch cut: (-oo, -1] U [1, oo) template inline Complex Complex::atanh() const { if ( i == 0 ) { if ( r > 1 ) { // [1, oo) return Complex( 0.25*std::log( (r + 1)*(r + 1)/((r - 1)*(r - 1)) ), Support::sign( i )*Support::PI2 ); } else if ( r == 1 ) { return Complex( Support::POS_INF, Support::NaN ); } else if ( r > 0 ) { return Complex( 0.5*std::log( (1 + r)/(1 - r) ), i ); } else if ( r == 0 ) { return *this; } else if ( r > -1 ) { return Complex( -0.5*std::log( (1 - r)/(1 + r) ), i ); } else if ( r == -1 ) { return Complex( Support::NEG_INF, Support::NaN ); } else { T rp = r + 1; T rm = r - 1; rp *= rp; rm *= rm; T logrprm = 0.25*std::log( rp/rm ); return Complex( logrprm, Support::sign( i )*Support::PI2 ); } } else if ( r == 0 ) { return Complex( r, std::atan( i ) ); } else { T opr = 1.0 + r; T omr = 1.0 - r; T ii = i*i; return Complex( 0.25*std::log( (ii + opr*opr)/(ii + omr*omr) ), 0.5*( std::atan2( i, opr ) - std::atan2( -i, omr ) ) ); } } // Branch cut: (-oo, 0] U (1, oo) template inline Complex Complex::asech() const { if ( i == 0 ) { if ( r < -1 ) { return Complex( 0.0, -Support::sign( i )*std::acos( 1/r ) ); } else if ( r == -1 ) { return Complex( 0.0, -Support::sign( i )*Support::PI ); } else if ( r < 0 ) { return Complex( std::log( -1/r + std::sqrt( -(1 - 1/r)*(1 + 1/r) ) ), -Support::sign( i )*Support::PI ); } else if ( r == 0 ) { return Complex( Support::POS_INF, Support::NaN ); } else if ( r <= 1 ) { return Complex( std::log( 1/r + std::sqrt( (1/r + 1)*(1/r - 1) ) ), -Support::sign( i )*0.0 ); } else { return Complex( 0.0, -Support::sign( i )*std::acos( 1/r ) ); } } else if ( r == 0 ) { if ( i > 0 ) { return Complex( std::log( std::sqrt( 1 + 1/(i*i) ) + 1/i ), -Support::PI2 ); } else { return Complex( std::log( std::sqrt( 1 + 1/(i*i) ) - 1/i ), Support::PI2 ); } } else { T ss = r*r + i*i; T Rr = r/ss; T Rrp1 = Rr + 1; Rrp1 = Rrp1 * Rrp1; T Rrm1 = Rr - 1; Rrm1 = Rrm1 * Rrm1; T Ri = i/ss; Ri = Ri*Ri; T Rrp1pRi = std::sqrt( Rrp1 + Ri ); T Rrm1pRi = std::sqrt( Rrm1 + Ri ); T sum = 0.5*( Rrp1pRi + Rrm1pRi ); return Complex( -Complex( -i, ss - r ).csgn()*Complex( i, r ).csgn()*std::log( sum + std::sqrt(sum*sum - 1) ), Complex( -i, ss - r ).csgn()*( std::acos( 0.5*(Rrp1pRi - Rrm1pRi) ) ) ); } } // Branch cut: (-i, i) // NOT YET FINISHED template inline Complex Complex::acsch() const { if ( r == 0 ) { if ( i <= -1 ) { return Complex( r, -std::asin( 1/i ) ); } else if ( i == -1 ) { return Complex( r, -Support::PI2 ); } else if ( i < 0 ) { return Complex( Support::sign( r )*std::log( -1/i + std::sqrt( 1/(i*i) - 1 ) ), Support::PI2 ); } else if ( i == 0 ) { return Complex( Support::POS_INF, Support::NEG_INF ); } else if ( i < 1 ) { return Complex( Support::sign( r )*std::log( 1/i + std::sqrt( 1/(i*i) - 1 ) ), -Support::PI2 ); } else if ( i == 1 ) { return Complex( r, -Support::PI2 ); } else { return Complex( r, -std::asin( 1/i ) ); } } else if ( i == 0 ) { return Complex( std::log( 1/r + std::sqrt( 1/(r*r) + 1 ) ), -i ); } else { T ss = r*r + i*i; T p1 = i/ss; T p1p1 = p1 + 1; p1p1 = p1p1 * p1p1; T p1m1 = p1 - 1; p1m1 = p1m1 * p1m1; T p2 = r/ss; p2 = p2*p2; T p1p1p2 = std::sqrt( p1p1 + p2 ); T p1m1p2 = std::sqrt( p1m1 + p2 ); T sum = 0.5*( p1p1p2 + p1m1p2 ); return Complex( Complex( r, -i ).csgn()*std::log( sum + std::sqrt(sum*sum - 1) ), std::asin( 0.5*(p1m1p2 - p1p1p2) ) ); } } // Branch cut: [-1, 1] // NOT YET FINISHED template inline Complex Complex::acoth() const { if ( i == 0 ) { if ( r < -1 ) { return Complex( 0.5*std::log( (r + 1)/(r - 1) ), -i ); } else if ( r == -1 ) { return Complex( Support::NEG_INF, Support::NaN ); } else if ( r < 0 ) { return Complex( 0.5*std::log( (r + 1)/(1 - r) ), -Support::sign( i )*Support::PI2 ); } else if ( r == 0 ) { return Complex( r, -Support::sign( i )*Support::PI2 ); } else if ( r < 1 ) { return Complex( 0.5*std::log( (r + 1)/(1 - r) ), -Support::sign( i )*Support::PI2 ); } else if ( r == 1 ) { return Complex( Support::POS_INF, Support::NaN ); } else { return Complex( 0.5*std::log( (r + 1)/(r - 1) ), -i ); } } else if ( r == 0 ) { if ( i > 0 ) { return Complex( r, -Support::PI2 + std::atan( i ) ); } else { return Complex( r, Support::PI2 + std::atan( i ) ); } } else { T rp1 = r + 1.0; T rm1 = r - 1.0; T ii = i*i; return Complex( 0.25*std::log( (ii + rp1*rp1)/(ii + rm1*rm1) ), 0.5*( std::atan2( i, rp1 ) - std::atan2( i, rm1 ) ) ); } } template inline Complex Complex::bessel_J( int n ) const { if ( n < 0 ) { return (n & 1) ? -bessel_J( -n ) : bessel_J( -n ); } Complex z = *this / 2.0; Complex term = 1.0; for ( int i = 1; i <= n; ++i ) { term *= z/i; } Complex z2 = z.sqr(); Complex result = term; Complex result_old = term; for ( T i = 1; ; i += 2.0 ) { term *= z2 / (i*(n + i)); result -= term; term *= z2 / ((i + 1.0)*(n + i + 1.0)); result += term; if ( result_old == result ) { return result; } result_old = result; } } /****************************************** * Integer Functions ******************************************/ // (a + bi) -> ceil(a) + ceil(b)i template inline Complex Complex::ceil() const { return Complex( std::ceil(r), std::ceil(i) ); } // (a + bi) -> floor(a) + floor(b)i template inline Complex Complex::floor() const { return Complex( std::floor(r), std::floor(i) ); } /****************************************** * Horner's Rule * * The polynomial is defined by giving the highest * coefficient first: * * n - 1 n - 2 * v[0]*z + v[1]*z + ... + v[n-2]*z + v[n-1] * * This is the same as with Matlab. ******************************************/ template inline Complex Complex::horner( T * v, unsigned int n ) const { if ( n == 0 ) { return ZERO; } if ( i == 0 ) { // real T ar = *v; for ( unsigned int j = 1; j < n; ++j ) { ar = ar*r + *(++v); } return Complex( ar, 0 ); } else if ( r == 0 ) { // imaginary T ar = *v; T ai = 0; for ( unsigned int j = 1; j < n; ++j ) { T aR = ar; ar = -ai*i + *(++v); ai = aR*i; } return Complex( ar, ai ); } else { // complex T ar = *v; T ai = 0; for ( unsigned int j = 1; j < n; ++j ) { T aR = ar; ar = ar*r - ai*i + *(++v); ai = aR*i + ai*r; } return Complex( ar, ai ); } } template inline Complex Complex::horner( T * v, T * c, unsigned int n ) const { if ( n == 0 ) { return ZERO; } if ( i == 0 ) { // real T ar = *v; for ( unsigned int j = 1; j < n; ++j ) { T dr = r - *(++c); ar = ar*dr + *(++v); } return Complex( ar, 0 ); } else if ( r == 0 ) { // imaginary T ar = *v; T ai = 0; for ( unsigned int j = 1; j < n; ++j ) { T dr = -*(++c); T aR = ar; ar = ar*dr - ai*i + *(++v); ai = aR*i + ai*dr; } return Complex( ar, ai ); } else { // complex T ar = *v; T ai = 0; for ( unsigned int j = 1; j < n; ++j ) { T dr = r - *(++c); T aR = ar; ar = ar*dr - ai*i + *(++v); ai = aR*i + ai*dr; } return Complex( ar, ai ); } } template inline Complex Complex::horner( Complex * v, unsigned int n ) const { if ( n == 0 ) { return ZERO; } if ( i == 0 ) { // real T ar = (*v).r; T ai = (*v).i; for ( unsigned int j = 1; j < n; ++j ) { ar = ar*r + (*(++v)).r; ai = ai*r + (*v).i; } return Complex( ar, ai ); } else if ( r == 0 ) { // imaginary T ar = (*v).r; T ai = (*v).i; for ( unsigned int j = 1; j < n; ++j ) { T aR = ar; ar = -ai*i + (*(++v)).r; ai = aR*i + (*v).i; } return Complex( ar, ai ); } else { // complex T ar = (*v).r; T ai = (*v).i; for ( unsigned int j = 1; j < n; ++j ) { T aR = ar; ar = ar*r - ai*i + (*(++v)).r; ai = aR*i + ai*r + (*v).i; } return Complex( ar, ai ); } } template inline Complex Complex::horner( Complex * v, T * c, unsigned int n ) const { if ( n == 0 ) { return ZERO; } if ( i == 0 ) { // real T ar = (*v).r; T ai = (*v).i; for ( unsigned int j = 1; j < n; ++j ) { T dr = r - *(++c); ar = ar*dr + (*(++v)).r; ai = ai*dr + (*v).i; } return Complex( ar, ai ); } else if ( r == 0 ) { // imaginary T ar = (*v).r; T ai = (*v).i; for ( unsigned int j = 1; j < n; ++j ) { T dr = -*(++c); T aR = ar; ar = ar*dr - ai*i + (*(++v)).r; ai = aR*i + ai*dr + (*v).i; } return Complex( ar, ai ); } else { // complex T ar = (*v).r; T ai = (*v).i; for ( unsigned int j = 1; j < n; ++j ) { T dr = r - *(++c); T aR = ar; ar = ar*dr - ai*i + (*(++v)).r; ai = aR*i + ai*dr + (*v).i; } return Complex( ar, ai ); } } template inline Complex Complex::horner( T * v, Complex * c, unsigned int n ) const { if ( n == 0 ) { return ZERO; } if ( i == 0 ) { // real T ar = *v; T ai = 0; for ( unsigned int j = 1; j < n; ++j ) { T dr = r - (*(++c)).r; T di = -(*c).i; T aR = ar; ar = ar*dr - ai*di + *(++v); ai = aR*di + ai*dr; } return Complex( ar, ai ); } else if ( r == 0 ) { // imaginary T ar = *v; T ai = 0.0; for ( unsigned int j = 1; j < n; ++j ) { T dr = -(*(++c)).r; T di = i - (*c).i; T aR = ar; ar = ar*dr - ai*di + *(++v); ai = aR*di + ai*dr; } return Complex( ar, ai ); } else { // complex T ar = *v; T ai = 0.0; for ( unsigned int j = 1; j < n; ++j ) { T dr = r - (*(++c)).r; T di = i - (*c).i; T aR = ar; ar = ar*dr - ai*di + *(++v); ai = aR*di + ai*dr; } return Complex( ar, ai ); } } template inline Complex Complex::horner( Complex * v, Complex * c, unsigned int n ) const { if ( n == 0 ) { return ZERO; } if ( i == 0 ) { // real T ar = (*v).r; T ai = (*v).i; for ( unsigned int j = 1; j < n; ++j ) { T dr = r - (*(++c)).r; T di = -(*c).i; T aR = ar; ar = ar*dr - ai*di + (*(++v)).r; ai = aR*di + ai*dr + (*v).i; } return Complex( ar, ai ); } else if ( r == 0 ) { // imaginary T ar = (*v).r; T ai = (*v).i; for ( unsigned int j = 1; j < n; ++j ) { T dr = -(*(++c)).r; T di = i - (*c).i; T aR = ar; ar = ar*dr - ai*di + (*(++v)).r; ai = aR*di + ai*dr + (*v).i; } return Complex( ar, ai ); } else { // complex T ar = (*v).r; T ai = (*v).i; for ( unsigned int j = 1; j < n; ++j ) { T dr = r - (*(++c)).r; T di = i - (*c).i; T aR = ar; ar = ar*dr - ai*di + (*(++v)).r; ai = aR*di + ai*dr + (*v).i; } return Complex( ar, ai ); } } /****************************************** * Random Factories ******************************************/ // -> a + bi template inline Complex Complex::random() { return Complex( (static_cast( rand() ))/RAND_MAX, (static_cast( rand() ))/RAND_MAX ); } // -> 0 + bi template inline Complex Complex::random_imag() { return Complex( 0.0, (static_cast( rand() ))/RAND_MAX ); } // -> a + 0i template inline Complex Complex::random_real() { return Complex( (static_cast( rand() ))/RAND_MAX, 0.0 ); } /****************************************** * Binary Arithmetic Operators ******************************************/ // (a + bi) + (c + di) -> (a + c) + (b + d)i template inline Complex Complex::operator + ( const Complex & z ) const { return Complex( r + z.r, i + z.i ); } // (a + bi) + x -> (a + x) + bi template inline Complex Complex::operator + ( T x ) const { return Complex( r + x, i ); } // x + (a + bi) -> (a + x) + bi template Complex operator + ( T x, const Complex & z ) { return Complex( x + z.real(), z.imag_i() ); } template Complex operator + ( long x, const Complex & z ) { return Complex( static_cast( x ) + z.real(), z.imag_i() ); } // (a + bi) - (c + di) -> (a - c) + (b - d)i template inline Complex Complex::operator - ( const Complex & z ) const { return Complex( r - z.r, i - z.i ); } // (a + bi) - x -> (a - x) + bi template inline Complex Complex::operator - ( T x ) const { return Complex( r - x, i ); } // x - (a + bi) -> (x + a) - bi template Complex operator - ( T x, const Complex & z ) { return Complex( x - z.real(), -z.imag_i() ); } template Complex operator - ( long x, const Complex & z ) { return Complex( static_cast( x ) - z.real(), -z.imag_i() ); } template inline Complex Complex::operator * ( const Complex & z ) const { return Complex( r*z.r - i*z.i, r*z.i + i*z.r ); } template inline Complex Complex::operator * ( T x ) const { if ( Support::is_inf( x ) && norm() > 0 ) { return Complex( ( ( r == 0 )?Support::sign(x):x )*r, ( ( i == 0 )?Support::sign(x):x )*i ); } else { return Complex( x*r, x*i ); } } template Complex operator * ( T x, const Complex & z ) { return Complex( x*z.real(), x*z.imag_i() ); } template Complex operator * ( long x, const Complex & z ) { return Complex( static_cast( x )*z.real(), static_cast( x )*z.imag_i() ); } template inline Complex Complex::operator / ( const Complex & z ) const { T denom = z.norm(); return Complex( (r*z.r + i*z.i)/denom, (-r*z.i + i*z.r)/denom ); } template inline Complex Complex::operator / ( T x ) const { if ( ( x == 0.0 ) && ( norm() > 0 ) ) { return Complex( r / ( ( r == 0 )?Support::sign( x ):x ), i / ( ( i == 0 )?Support::sign( x ):x ) ); } else { return Complex( r/x, i/x ); } } template Complex operator / ( T x, const Complex & z ) { T mltplr = x/z.norm(); return Complex( mltplr*z.real(), -mltplr*z.imag_i() ); } template Complex operator / ( long x, const Complex & z ) { T mltplr = static_cast( x )/z.norm(); return Complex( mltplr*z.real(), -mltplr*z.imag_i() ); } /****************************************** * Unary Arithmetic Operators ******************************************/ // -(a + bi) -> -a - bi template inline Complex Complex::operator - () const { return Complex( -r, -i ); } /****************************************** * Binary Boolean Operators ******************************************/ // (a + bi) == (c + di) -> (a == c) && (b == d) template inline bool Complex::operator == ( const Complex & z ) const { return ( r == z.r ) && ( i == z.i ); } // (a + bi) == x -> (a == x) && (b == 0) template inline bool Complex::operator == ( T x ) const { return ( r == x ) && ( i == 0.0 ); } // (a + bi) != (c + di) -> (a != c) || (b != d) template inline bool Complex::operator != ( const Complex & z ) const { return ( r != z.r ) || ( i != z.i ); } // (a + bi) != x -> (a != x) || (b != 0) template inline bool Complex::operator != ( T x ) const { return ( r != x ) || ( i != 0.0 ); } // x == (a + bi) -> (x == a) && (b == 0) template bool operator == ( T x, const Complex & z ) { return ( z.real() == x ) && ( z.imag_i() == 0.0 ); } template bool operator == ( long x, const Complex & z ) { return ( z.real() == static_cast( x ) ) && ( z.imag_i() == 0.0 ); } // x != (a + bi) -> (x != a) || (b != 0) template bool operator != ( T x, const Complex & z ) { return ( z.real() != x ) || ( z.imag_i() != 0.0 ); } template bool operator != ( long x, const Complex & z ) { return ( z.real() != static_cast( x ) ) || ( z.imag_i() != 0.0 ); } template std::ostream & operator << ( std::ostream & out, const Complex & z ) { Support::print_real( z.real(), out ); Support::print_imaginary( z.imag_i(), Complex::get_symbol(), out ); return out; } /****************************************** * ************************************** * * * * * * * Procedural Functions * * * * * * * ************************************** * ******************************************/ /****************************************** * Real-valued Functions ******************************************/ template T real( const Complex & z ) { return z.real(); } template T imag_i( const Complex & z ) { return z.imag_i(); } template T csgn( const Complex & z ) { return z.csgn(); } template T abs( const Complex & z ) { return z.abs(); } template T norm( const Complex & z ) { return z.norm(); } template T abs_imag( const Complex & z ) { return z.abs_imag(); } template T norm_imag( const Complex & z ) { return z.norm_imag(); } /****************************************** * Complex-valued Functions ******************************************/ template Complex imag( const Complex & z ) { return z.imag(); } template Complex conj( const Complex & z ) { return z.conj(); } template Complex signum( const Complex & z ) { return z.signum(); } template Complex sqr( const Complex & z ) { return z.sqr(); } template Complex sqrt( const Complex & z ) { return z.sqrt(); } /****************************************** * Exponential and Logarithmic Functions ******************************************/ template Complex exp( const Complex & z ) { return z.exp(); } template Complex log( const Complex & z ) { return z.log(); } template Complex log10( const Complex & z ) { return z.log10(); } template Complex pow( const Complex & z, const Complex & w ) { return z.pow( w ); } template Complex pow( const Complex & z, T x ) { return z.pow( x ); } template Complex inverse( const Complex & z ) { return z.inverse(); } /****************************************** * Trigonometric and Hyperbolic Functions ******************************************/ template Complex sin( const Complex & z ) { return z.sin(); } template Complex cos( const Complex & z ) { return z.cos(); } template Complex tan( const Complex & z ) { return z.tan(); } template Complex sec( const Complex & z ) { return z.sec(); } template Complex csc( const Complex & z ) { return z.csc(); } template Complex cot( const Complex & z ) { return z.cot(); } template Complex sinh( const Complex & z ) { return z.sinh(); } template Complex cosh( const Complex & z ) { return z.cosh(); } template Complex tanh( const Complex & z ) { return z.tanh(); } template Complex sech( const Complex & z ) { return z.sech(); } template Complex csch( const Complex & z ) { return z.csch(); } template Complex coth( const Complex & z ) { return z.coth(); } template Complex asin( const Complex & z ) { return z.asin(); } template Complex acos( const Complex & z ) { return z.acos(); } template Complex atan( const Complex & z ) { return z.atan(); } template Complex asec( const Complex & z ) { return z.asec(); } template Complex acsc( const Complex & z ) { return z.acsc(); } template Complex acot( const Complex & z ) { return z.acot(); } template Complex asinh( const Complex & z ) { return z.asinh(); } template Complex acosh( const Complex & z ) { return z.acosh(); } template Complex atanh( const Complex & z ) { return z.atanh(); } template Complex asech( const Complex & z ) { return z.asech(); } template Complex acsch( const Complex & z ) { return z.acsch(); } template Complex acoth( const Complex & z ) { return z.acoth(); } template Complex bessel_J( int n, const Complex & z ) { return z.bessel_J( n ); } /****************************************** * Integer Functions ******************************************/ template Complex floor( const Complex & z ) { return z.floor(); } template Complex ceil( const Complex & z ) { return z.ceil(); } /****************************************** * Horner's Rule ******************************************/ template Complex horner( const Complex & z, T * v, unsigned int n ) { return z.horner( v, n ); } template Complex horner( const Complex & z, T * v, T * c, unsigned int n ) { return z.horner( v, c, n ); } template Complex horner( const Complex & z, Complex * v, unsigned int n ) { return z.horner( v, n ); } template Complex horner( const Complex & z, Complex * v, T * c, unsigned int n ) { return z.horner( v, c, n ); } template Complex horner( const Complex & z, T * v, Complex * c, unsigned int n ) { return z.horner( v, c, n ); } template Complex horner( const Complex & z, Complex * v, Complex * c, unsigned int n ) { return z.horner( v, c, n ); } /************************************************** * ********************************************** * * * * * * * Double-precision Floating-point * * * * Instance of Template * * * * * * * ********************************************** * **************************************************/ template class Complex; template <> const Complex Complex::ZERO = Complex( 0, 0 ); template <> const Complex Complex::ONE = Complex( 1, 0 ); template <> const Complex Complex::I = Complex( 0, 1 ); template <> const Complex Complex::UNITS[2] = { Complex::ONE, Complex::I }; template <> char Complex::imaginary_symbol = 'i'; template std::ostream & operator << ( std::ostream & out, const Complex & ); template Complex operator + ( double, const Complex & ); template Complex operator + ( long, const Complex & ); template Complex operator - ( double, const Complex & ); template Complex operator - ( long, const Complex & ); template Complex operator * ( double, const Complex & ); template Complex operator * ( long, const Complex & ); template Complex operator / ( double, const Complex & ); template Complex operator / ( long, const Complex & ); template bool operator == ( double, const Complex & ); template bool operator == ( long, const Complex & ); template bool operator != ( double, const Complex & ); template bool operator != ( long, const Complex & ); template double real( const Complex & ); template double imag_i( const Complex & ); template double csgn( const Complex & ); template double abs( const Complex & ); template double norm( const Complex & ); template double abs_imag( const Complex & ); template double norm_imag( const Complex & ); template Complex imag( const Complex & ); template Complex conj( const Complex & ); template Complex signum( const Complex & ); template Complex sqr( const Complex & ); template Complex sqrt( const Complex & ); template Complex exp( const Complex & ); template Complex log( const Complex & ); template Complex log10( const Complex & ); template Complex pow( const Complex &, const Complex & ); template Complex pow( const Complex &, double ); template Complex inverse( const Complex & ); template Complex sin( const Complex & ); template Complex cos( const Complex & ); template Complex tan( const Complex & ); template Complex sec( const Complex & ); template Complex csc( const Complex & ); template Complex cot( const Complex & ); template Complex sinh( const Complex & ); template Complex cosh( const Complex & ); template Complex tanh( const Complex & ); template Complex sech( const Complex & ); template Complex csch( const Complex & ); template Complex coth( const Complex & ); template Complex asin( const Complex & ); template Complex acos( const Complex & ); template Complex atan( const Complex & ); template Complex asec( const Complex & ); template Complex acsc( const Complex & ); template Complex acot( const Complex & ); template Complex asinh( const Complex & ); template Complex acosh( const Complex & ); template Complex atanh( const Complex & ); template Complex asech( const Complex & ); template Complex acsch( const Complex & ); template Complex acoth( const Complex & ); template Complex bessel_J( int, const Complex & ); template Complex floor( const Complex & ); template Complex ceil( const Complex & ); template Complex horner( const Complex &, double *, unsigned int ); template Complex horner( const Complex &, double *, double *, unsigned int ); template Complex horner( const Complex &, Complex *, unsigned int ); template Complex horner( const Complex &, Complex *, double *, unsigned int ); template Complex horner( const Complex &, double *, Complex *, unsigned int ); template Complex horner( const Complex &, Complex *, Complex *, unsigned int ); /************************************************** * ********************************************** * * * * * * * Floating-point Instance of Template * * * * * * * ********************************************** * **************************************************/ template class Complex; template <> const Complex Complex::ZERO = Complex( 0, 0 ); template <> const Complex Complex::ONE = Complex( 1, 0 ); template <> const Complex Complex::I = Complex( 0, 1 ); template <> const Complex Complex::UNITS[2] = { Complex::ONE, Complex::I }; template <> char Complex::imaginary_symbol = 'i'; template std::ostream & operator << ( std::ostream & out, const Complex & ); template Complex operator + ( float, const Complex & ); template Complex operator + ( long, const Complex & ); template Complex operator - ( float, const Complex & ); template Complex operator - ( long, const Complex & ); template Complex operator * ( float, const Complex & ); template Complex operator * ( long, const Complex & ); template Complex operator / ( float, const Complex & ); template Complex operator / ( long, const Complex & ); template bool operator == ( float, const Complex & ); template bool operator == ( long, const Complex & ); template bool operator != ( float, const Complex & ); template bool operator != ( long, const Complex & ); template float real( const Complex & ); template float imag_i( const Complex & ); template float csgn( const Complex & ); template float abs( const Complex & ); template float norm( const Complex & ); template float abs_imag( const Complex & ); template float norm_imag( const Complex & ); template Complex imag( const Complex & ); template Complex conj( const Complex & ); template Complex signum( const Complex & ); template Complex sqr( const Complex & ); template Complex sqrt( const Complex & ); template Complex exp( const Complex & ); template Complex log( const Complex & ); template Complex log10( const Complex & ); template Complex pow( const Complex &, const Complex & ); template Complex pow( const Complex &, float ); template Complex inverse( const Complex & ); template Complex sin( const Complex & ); template Complex cos( const Complex & ); template Complex tan( const Complex & ); template Complex sec( const Complex & ); template Complex csc( const Complex & ); template Complex cot( const Complex & ); template Complex sinh( const Complex & ); template Complex cosh( const Complex & ); template Complex tanh( const Complex & ); template Complex sech( const Complex & ); template Complex csch( const Complex & ); template Complex coth( const Complex & ); template Complex asin( const Complex & ); template Complex acos( const Complex & ); template Complex atan( const Complex & ); template Complex asec( const Complex & ); template Complex acsc( const Complex & ); template Complex acot( const Complex & ); template Complex asinh( const Complex & ); template Complex acosh( const Complex & ); template Complex atanh( const Complex & ); template Complex asech( const Complex & ); template Complex acsch( const Complex & ); template Complex acoth( const Complex & ); template Complex bessel_J( int, const Complex & ); template Complex floor( const Complex & ); template Complex ceil( const Complex & ); template Complex horner( const Complex &, float *, unsigned int ); template Complex horner( const Complex &, float *, float *, unsigned int ); template Complex horner( const Complex &, Complex *, unsigned int ); template Complex horner( const Complex &, Complex *, float *, unsigned int ); template Complex horner( const Complex &, float *, Complex *, unsigned int ); template Complex horner( const Complex &, Complex *, Complex *, unsigned int ); /************************************************************************ * ******************************************************************** * * * * * * * Long Double-Precision Floating-point Instance of Template * * * * * * * ******************************************************************** * ************************************************************************/ template class Complex; template <> const Complex Complex::ZERO = Complex( 0, 0 ); template <> const Complex Complex::ONE = Complex( 1, 0 ); template <> const Complex Complex::I = Complex( 0, 1 ); template <> const Complex Complex::UNITS[2] = { Complex::ONE, Complex::I }; template <> char Complex::imaginary_symbol = 'i'; template std::ostream & operator << ( std::ostream & out, const Complex & ); template Complex operator + ( long double, const Complex & ); template Complex operator + ( long, const Complex & ); template Complex operator - ( long double, const Complex & ); template Complex operator - ( long, const Complex & ); template Complex operator * ( long double, const Complex & ); template Complex operator * ( long, const Complex & ); template Complex operator / ( long double, const Complex & ); template Complex operator / ( long, const Complex & ); template bool operator == ( long double, const Complex & ); template bool operator == ( long, const Complex & ); template bool operator != ( long double, const Complex & ); template bool operator != ( long, const Complex & ); template long double real( const Complex & ); template long double imag_i( const Complex & ); template long double csgn( const Complex & ); template long double abs( const Complex & ); template long double norm( const Complex & ); template long double abs_imag( const Complex & ); template long double norm_imag( const Complex & ); template Complex imag( const Complex & ); template Complex conj( const Complex & ); template Complex signum( const Complex & ); template Complex sqr( const Complex & ); template Complex sqrt( const Complex & ); template Complex exp( const Complex & ); template Complex log( const Complex & ); template Complex log10( const Complex & ); template Complex pow( const Complex &, const Complex & ); template Complex pow( const Complex &, long double ); template Complex inverse( const Complex & ); template Complex sin( const Complex & ); template Complex cos( const Complex & ); template Complex tan( const Complex & ); template Complex sec( const Complex & ); template Complex csc( const Complex & ); template Complex cot( const Complex & ); template Complex sinh( const Complex & ); template Complex cosh( const Complex & ); template Complex tanh( const Complex & ); template Complex sech( const Complex & ); template Complex csch( const Complex & ); template Complex coth( const Complex & ); template Complex asin( const Complex & ); template Complex acos( const Complex & ); template Complex atan( const Complex & ); template Complex asec( const Complex & ); template Complex acsc( const Complex & ); template Complex acot( const Complex & ); template Complex asinh( const Complex & ); template Complex acosh( const Complex & ); template Complex atanh( const Complex & ); template Complex asech( const Complex & ); template Complex acsch( const Complex & ); template Complex acoth( const Complex & ); template Complex bessel_J( int, const Complex & ); template Complex floor( const Complex & ); template Complex ceil( const Complex & ); template Complex horner( const Complex &, long double *, unsigned int ); template Complex horner( const Complex &, long double *, long double *, unsigned int ); template Complex horner( const Complex &, Complex *, unsigned int ); template Complex horner( const Complex &, Complex *, long double *, unsigned int ); template Complex horner( const Complex &, long double *, Complex *, unsigned int ); template Complex horner( const Complex &, Complex *, Complex *, unsigned int );