CMS 3D CMS Logo

/data/refman/pasoursint/CMSSW_5_3_3/src/DataFormats/Math/interface/FastMath.h

Go to the documentation of this file.
00001 #ifndef DataFormats_Math_FastMath_h
00002 #define DataFormats_Math_FastMath_h
00003 // faster function will a limited precision
00004 
00005 #include<cmath>
00006 #include<utility>
00007 #ifdef __SSE2__
00008 # include <emmintrin.h>
00009 #endif
00010 namespace fastmath {
00011   inline float invSqrt( float in ) {
00012 #ifndef __SSE2__
00013     return 1.f/std::sqrt(in);
00014 #else
00015     float out;
00016     _mm_store_ss( &out, _mm_rsqrt_ss( _mm_load_ss( &in ) ) ); // compiles to movss, rsqrtss, movss
00017     // return out; // already good enough!
00018     return out * (1.5f - 0.5f * in * out * out); // One (more?) round of Newton's method
00019 #endif
00020   }
00021 
00022   inline double invSqrt(double in ) {
00023     return 1./std::sqrt(in);
00024   }
00025   
00026 }
00027   
00028 namespace fastmath_details {
00029   const double _2pi = (2.0 * 3.1415926535897932384626434);
00030   const float _2pif = float(_2pi);
00031   extern float atanbuf_[257 * 2];
00032   extern double datanbuf_[513 * 2];
00033 }
00034 
00035 namespace  fastmath {
00036 
00037   // =====================================================================
00038   // arctan, single-precision; returns phi and r (or 1/r if overR=true)
00039   // =====================================================================
00040   inline std::pair<float,float> atan2r(float y_, float x_, bool overR=false) {
00041     using namespace fastmath_details;
00042     float mag2 = x_ * x_ + y_ * y_;
00043     if(!(mag2 > 0))  {  return std::pair<float,float>(0.f,0.f); }   // degenerate case
00044     
00045     // float r_ = std::sqrt(mag2);
00046     float rinv = invSqrt(mag2);
00047     unsigned int flags = 0;
00048     float x, y;
00049     union {
00050       float f;
00051       int i;
00052     } yp;
00053     yp.f = 32768.f;
00054     if (y_ < 0 ) { flags |= 4; y_ = -y_; }
00055     if (x_ < 0 ) { flags |= 2; x_ = -x_; }
00056     if (y_ > x_) {
00057       flags |= 1;
00058       x = rinv * y_; y = rinv * x_; yp.f += y;
00059     }
00060     else {
00061       x = rinv * x_; y = rinv * y_; yp.f += y;
00062     }
00063     int ind = (yp.i & 0x01FF) * 2;
00064     
00065     float* asbuf = (float*)(atanbuf_ + ind);
00066     float sv = yp.f - 32768.f;
00067     float cv = asbuf[0];
00068     float asv = asbuf[1];
00069     sv = y * cv - x * sv;    // delta sin value
00070     // ____ compute arcsin directly
00071     float asvd = 6.f + sv * sv;   sv *= float(1.0f / 6.0f);
00072     float th = asv + asvd * sv;
00073     if (flags & 1) { th = (_2pif / 4.f) - th; }
00074     if (flags & 2) { th = (_2pif / 2.f) - th; }
00075     if (flags & 4) { th = -th; }
00076     return std::pair<float,float>(th,overR ? rinv : rinv*mag2);    
00077   }
00078   
00079   // =====================================================================
00080   // arctan, double-precision; returns phi and r (or 1/r if overR=true)
00081   // =====================================================================
00082   inline std::pair<double, double> atan2r(double y_, double x_, bool overR=false) {
00083     using namespace fastmath_details;
00084     // assert(ataninited);
00085     double mag2 = x_ * x_ + y_ * y_;
00086     if(!(mag2 > 0)) { return std::pair<double, double>(0.,0.); }   // degenerate case
00087     
00088     double r_ = std::sqrt(mag2);
00089     double rinv = 1./r_;
00090     unsigned int flags = 0;
00091     double x, y;
00092     const double _2p43 = 65536.0 * 65536.0 * 2048.0;
00093     union {
00094       double d;
00095       int i[2];
00096     } yp;
00097 
00098     yp.d = _2p43;
00099     if (y_ < 0) { flags |= 4; y_ = -y_; }
00100     if (x_ < 0) { flags |= 2; x_ = -x_; }
00101     if (y_ > x_) {
00102       flags |= 1;
00103       x = rinv * y_; y = rinv * x_; yp.d += y;
00104     }
00105     else {
00106       x = rinv * x_; y = rinv * y_; yp.d += y;
00107     }
00108 
00109     int ind = (yp.i[0] & 0x03FF) * 2;  // 0 for little indian
00110     
00111     double* dasbuf = (double*)(datanbuf_ + ind);
00112     double sv = yp.d - _2p43; // index fraction
00113     double cv = dasbuf[0];
00114     double asv = dasbuf[1];
00115     sv = y * cv - x * sv;    // delta sin value
00116     // double sv = y *(cv-x);
00117     // ____ compute arcsin directly
00118     double asvd = 6 + sv * sv;   sv *= double(1.0 / 6.0);
00119     double th = asv + asvd * sv;
00120     if (flags & 1) { th = (_2pi / 4) - th; }
00121     if (flags & 2) { th = (_2pi / 2) - th; }
00122     if (flags & 4) { th = -th; }
00123     return std::pair<double,double>(th,overR ? rinv : r_);    
00124   }
00125  
00126   // return eta phi saving some computation
00127   template<typename T>
00128   inline  std::pair<T,T> etaphi(T x, T y, T z) {
00129     std::pair<T,T> por = atan2r(y,x, true);
00130     x = z*por.second;
00131     return std::pair<float,float>( std::log(x+std::sqrt(x*x+T(1))), por.first);
00132   }
00133 
00134 }
00135 
00136 
00137 #endif