|
Rcpp Version 0.9.10
|
00001 // -*- mode: C++; c-indent-level: 4; c-basic-offset: 4; tab-width: 8 -*- 00002 // 00003 // complex.h: Rcpp R/C++ interface class library -- complex 00004 // 00005 // Copyright (C) 2010 - 2011 Dirk Eddelbuettel and Romain Francois 00006 // 00007 // This file is part of Rcpp. 00008 // 00009 // Rcpp is free software: you can redistribute it and/or modify it 00010 // under the terms of the GNU General Public License as published by 00011 // the Free Software Foundation, either version 2 of the License, or 00012 // (at your option) any later version. 00013 // 00014 // Rcpp is distributed in the hope that it will be useful, but 00015 // WITHOUT ANY WARRANTY; without even the implied warranty of 00016 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00017 // GNU General Public License for more details. 00018 // 00019 // You should have received a copy of the GNU General Public License 00020 // along with Rcpp. If not, see <http://www.gnu.org/licenses/>. 00021 00022 #ifndef Rcpp__sugar__complex_h 00023 #define Rcpp__sugar__complex_h 00024 00025 #ifdef HAVE_HYPOT 00026 # define RCPP_HYPOT ::hypot 00027 #else 00028 # define RCPP_HYPOT ::Rf_pythag 00029 #endif 00030 00031 namespace Rcpp{ 00032 namespace sugar{ 00033 00034 00035 template <bool NA, typename OUT, typename T, typename FunPtr> 00036 class SugarComplex : public Rcpp::VectorBase< 00037 Rcpp::traits::r_sexptype_traits<OUT>::rtype , 00038 NA, 00039 SugarComplex<NA,OUT,T,FunPtr> 00040 > { 00041 public: 00042 00043 typedef Rcpp::VectorBase<CPLXSXP,NA,T> VEC_TYPE ; 00044 00045 SugarComplex( FunPtr ptr_, const VEC_TYPE & vec_) : ptr(ptr_), vec(vec_){} 00046 00047 inline OUT operator[]( int i) const { 00048 Rcomplex x = vec[i] ; 00049 if( Rcpp::traits::is_na<CPLXSXP>( x ) ) 00050 return Rcpp::traits::get_na< Rcpp::traits::r_sexptype_traits<OUT>::rtype >() ; 00051 return ptr( x ); 00052 } 00053 inline int size() const { return vec.size() ; } 00054 00055 private: 00056 FunPtr ptr ; 00057 const VEC_TYPE& vec ; 00058 }; 00059 } // sugar 00060 00061 namespace internal{ 00062 inline double complex__Re( Rcomplex x){ return x.r ; } 00063 inline double complex__Im( Rcomplex x){ return x.i ; } 00064 inline double complex__Mod( Rcomplex x){ return ::sqrt( x.i * x.i + x.r * x.r) ; } 00065 inline Rcomplex complex__Conj( Rcomplex x){ 00066 Rcomplex y ; 00067 y.r = x.r; 00068 y.i = -x.i ; 00069 return y ; 00070 } 00071 // TODO: this does not use HAVE_C99_COMPLEX as in R, perhaps it should 00072 inline Rcomplex complex__exp( Rcomplex x){ 00073 Rcomplex y ; 00074 double expx = ::exp(x.r); 00075 y.r = expx * ::cos(x.i); 00076 y.i = expx * ::sin(x.i); 00077 return y ; 00078 } 00079 inline Rcomplex complex__log( Rcomplex x){ 00080 Rcomplex y ; 00081 y.i = ::atan2(x.i, x.r); 00082 y.r = ::log( RCPP_HYPOT( x.r, x.i ) ); 00083 return y ; 00084 } 00085 inline Rcomplex complex__sqrt(Rcomplex z){ 00086 Rcomplex r ; 00087 double mag; 00088 00089 if( (mag = RCPP_HYPOT(z.r, z.i)) == 0.0) 00090 r.r = r.i = 0.0; 00091 else if(z.r > 0) { 00092 r.r = ::sqrt(0.5 * (mag + z.r) ); 00093 r.i = z.i / r.r / 2; 00094 } 00095 else { 00096 r.i = ::sqrt(0.5 * (mag - z.r) ); 00097 if(z.i < 0) 00098 r.i = - r.i; 00099 r.r = z.i / r.i / 2; 00100 } 00101 return r ; 00102 } 00103 inline Rcomplex complex__cos(Rcomplex z){ 00104 Rcomplex r ; 00105 r.r = ::cos(z.r) * ::cosh(z.i); 00106 r.i = - ::sin(z.r) * ::sinh(z.i); 00107 return r ; 00108 } 00109 inline Rcomplex complex__cosh(Rcomplex z){ 00110 Rcomplex r; 00111 r.r = ::cos(-z.i) * ::cosh( z.r); 00112 r.i = - ::sin(-z.i) * ::sinh(z.r); 00113 return r ; 00114 } 00115 inline Rcomplex complex__sin(Rcomplex z){ 00116 Rcomplex r ; 00117 r.r = ::sin(z.r) * ::cosh(z.i); 00118 r.i = ::cos(z.r) * ::sinh(z.i); 00119 return r; 00120 } 00121 inline Rcomplex complex__tan(Rcomplex z){ 00122 Rcomplex r ; 00123 double x2, y2, den; 00124 x2 = 2.0 * z.r; 00125 y2 = 2.0 * z.i; 00126 den = ::cos(x2) + ::cosh(y2); 00127 r.r = ::sin(x2)/den; 00128 /* any threshold between -log(DBL_EPSILON) 00129 and log(DBL_XMAX) will do*/ 00130 if (ISNAN(y2) || ::fabs(y2) < 50.0) 00131 r.i = ::sinh(y2)/den; 00132 else 00133 r.i = (y2 <0 ? -1.0 : 1.0); 00134 return r ; 00135 } 00136 00137 inline Rcomplex complex__asin(Rcomplex z) 00138 { 00139 Rcomplex r ; 00140 double alpha, bet, t1, t2, x, y; 00141 x = z.r; 00142 y = z.i; 00143 t1 = 0.5 * RCPP_HYPOT(x + 1, y); 00144 t2 = 0.5 * RCPP_HYPOT(x - 1, y); 00145 alpha = t1 + t2; 00146 bet = t1 - t2; 00147 r.r = ::asin(bet); 00148 r.i = ::log(alpha + ::sqrt(alpha*alpha - 1)); 00149 if(y < 0 || (y == 0 && x > 1)) r.i *= -1; 00150 return r ; 00151 } 00152 00153 inline Rcomplex complex__acos(Rcomplex z) 00154 { 00155 Rcomplex r, Asin = complex__asin(z); 00156 r.r = M_PI_2 - Asin.r; 00157 r.i = - Asin.i; 00158 return r ; 00159 } 00160 00161 /* Complex Arctangent Function */ 00162 /* Equation (4.4.39) Abramowitz and Stegun */ 00163 /* with additional terms to force the branch cuts */ 00164 /* to agree with figure 4.4, p79. Continuity */ 00165 /* on the branch cuts (pure imaginary axis; x==0, |y|>1) */ 00166 /* is standard: z_asin() is continuous from the right */ 00167 /* if y >= 1, and continuous from the left if y <= -1. */ 00168 00169 inline Rcomplex complex__atan(Rcomplex z) 00170 { 00171 Rcomplex r; 00172 double x, y; 00173 x = z.r; 00174 y = z.i; 00175 r.r = 0.5 * ::atan(2 * x / ( 1 - x * x - y * y)); 00176 r.i = 0.25 * ::log((x * x + (y + 1) * (y + 1)) / 00177 (x * x + (y - 1) * (y - 1))); 00178 if(x*x + y*y > 1) { 00179 r.r += M_PI_2; 00180 if(x < 0 || (x == 0 && y < 0)) r.r -= M_PI; 00181 } 00182 return r ; 00183 } 00184 00185 00186 inline Rcomplex complex__acosh(Rcomplex z){ 00187 Rcomplex r, a = complex__acos(z); 00188 r.r = -a.i; 00189 r.i = a.r; 00190 return r ; 00191 } 00192 00193 inline Rcomplex complex__asinh(Rcomplex z){ 00194 Rcomplex r, b; 00195 b.r = -z.i; 00196 b.i = z.r; 00197 Rcomplex a = complex__asin(b); 00198 r.r = a.i; 00199 r.i = -a.r; 00200 return r ; 00201 } 00202 00203 inline Rcomplex complex__atanh(Rcomplex z){ 00204 Rcomplex r, b; 00205 b.r = -z.i; 00206 b.i = z.r; 00207 Rcomplex a = complex__atan(b); 00208 r.r = a.i; 00209 r.i = -a.r; 00210 return r ; 00211 } 00212 inline Rcomplex complex__sinh(Rcomplex z) 00213 { 00214 Rcomplex r, b; 00215 b.r = -z.i; 00216 b.i = z.r; 00217 Rcomplex a = complex__sin(b); 00218 r.r = a.i; 00219 r.i = -a.r; 00220 return r ; 00221 } 00222 00223 inline Rcomplex complex__tanh(Rcomplex z) 00224 { 00225 Rcomplex r, b; 00226 b.r = -z.i; 00227 b.i = z.r; 00228 Rcomplex a = complex__tan(b); 00229 r.r = a.i; 00230 r.i = -a.r; 00231 return r ; 00232 } 00233 00234 00235 00236 } // internal 00237 00238 #define RCPP_SUGAR_COMPLEX(__NAME__,__OUT__) \ 00239 template <bool NA, typename T> \ 00240 inline sugar::SugarComplex<NA,__OUT__,T, __OUT__ (*)(Rcomplex) > \ 00241 __NAME__( \ 00242 const VectorBase<CPLXSXP,NA,T>& t \ 00243 ){ \ 00244 return sugar::SugarComplex<NA,__OUT__,T, __OUT__ (*)(Rcomplex) >( \ 00245 internal::complex__##__NAME__, t \ 00246 ) ; \ 00247 } 00248 00249 RCPP_SUGAR_COMPLEX( Re, double ) 00250 RCPP_SUGAR_COMPLEX( Im, double ) 00251 RCPP_SUGAR_COMPLEX( Mod, double ) 00252 RCPP_SUGAR_COMPLEX( Conj, Rcomplex ) 00253 RCPP_SUGAR_COMPLEX( exp, Rcomplex ) 00254 RCPP_SUGAR_COMPLEX( log, Rcomplex ) 00255 RCPP_SUGAR_COMPLEX( sqrt, Rcomplex ) 00256 RCPP_SUGAR_COMPLEX( cos, Rcomplex ) 00257 RCPP_SUGAR_COMPLEX( sin, Rcomplex ) 00258 RCPP_SUGAR_COMPLEX( tan, Rcomplex ) 00259 RCPP_SUGAR_COMPLEX( acos, Rcomplex ) 00260 RCPP_SUGAR_COMPLEX( asin, Rcomplex ) 00261 RCPP_SUGAR_COMPLEX( atan, Rcomplex ) 00262 RCPP_SUGAR_COMPLEX( acosh, Rcomplex ) 00263 RCPP_SUGAR_COMPLEX( asinh, Rcomplex ) 00264 RCPP_SUGAR_COMPLEX( atanh, Rcomplex ) 00265 RCPP_SUGAR_COMPLEX( cosh, Rcomplex ) 00266 RCPP_SUGAR_COMPLEX( sinh, Rcomplex ) 00267 RCPP_SUGAR_COMPLEX( tanh, Rcomplex ) 00268 00269 #undef RCPP_SUGAR_COMPLEX 00270 00271 } // Rcpp 00272 #endif 00273