/* * sincos_common.h * The basic idea is to exploit Pade polynomials. * A lot of ideas were inspired by the cephes math library (by Stephen L. Moshier * moshier@na-net.ornl.gov) as well as actual code. * The Cephes library can be found here: http://www.netlib.org/cephes/ * * Created on: Jun 23, 2012 * Author: Danilo Piparo, Thomas Hauth, Vincenzo Innocente */ /* * VDT is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser Public License for more details. * * You should have received a copy of the GNU Lesser Public License * along with this program. If not, see . */ #include "vdtcore_common.h" #include #include #ifndef SINCOS_COMMON_H_ #define SINCOS_COMMON_H_ namespace vdt{ namespace details{ // double precision constants const double DP1sc = 7.85398125648498535156E-1; const double DP2sc = 3.77489470793079817668E-8; const double DP3sc = 2.69515142907905952645E-15; const double C1sin = 1.58962301576546568060E-10; const double C2sin =-2.50507477628578072866E-8; const double C3sin = 2.75573136213857245213E-6; const double C4sin =-1.98412698295895385996E-4; const double C5sin = 8.33333333332211858878E-3; const double C6sin =-1.66666666666666307295E-1; const double C1cos =-1.13585365213876817300E-11; const double C2cos = 2.08757008419747316778E-9; const double C3cos =-2.75573141792967388112E-7; const double C4cos = 2.48015872888517045348E-5; const double C5cos =-1.38888888888730564116E-3; const double C6cos = 4.16666666666665929218E-2; const double DP1 = 7.853981554508209228515625E-1; const double DP2 = 7.94662735614792836714E-9; const double DP3 = 3.06161699786838294307E-17; // single precision constants const float DP1F = 0.78515625; const float DP2F = 2.4187564849853515625e-4; const float DP3F = 3.77489497744594108e-8; const float T24M1 = 16777215.; //------------------------------------------------------------------------------ inline double get_sin_px(const double x){ double px=C1sin; px *= x; px += C2sin; px *= x; px += C3sin; px *= x; px += C4sin; px *= x; px += C5sin; px *= x; px += C6sin; return px; } //------------------------------------------------------------------------------ inline double get_cos_px(const double x){ double px=C1cos; px *= x; px += C2cos; px *= x; px += C3cos; px *= x; px += C4cos; px *= x; px += C5cos; px *= x; px += C6cos; return px; } //------------------------------------------------------------------------------ /// Reduce to 0 to 45 inline double reduce2quadrant(double x, int32_t& quad) { x = fabs(x); quad = int (ONEOPIO4 * x); // always positive, so (int) == std::floor quad = (quad+1) & (~1); const double y = double (quad); // Extended precision modular arithmetic return ((x - y * DP1) - y * DP2) - y * DP3; } //------------------------------------------------------------------------------ /// Sincos only for -45deg < x < 45deg inline void fast_sincos_m45_45( const double z, double & s, double &c ) { double zz = z * z; s = z + z * zz * get_sin_px(zz); c = 1.0 - zz * .5 + zz * zz * get_cos_px(zz); } //------------------------------------------------------------------------------ } // End namespace details /// Double precision sincos inline void fast_sincos( const double xx, double & s, double &c ) { // I have to use doubles to make it vectorise... int j; double x = details::reduce2quadrant(xx,j); const double signS = (j&4); j-=2; const double signC = (j&4); const double poly = j&2; details::fast_sincos_m45_45(x,s,c); //swap if( poly==0 ) { const double tmp = c; c=s; s=tmp; } if(signC == 0.) c = -c; if(signS != 0.) s = -s; if (xx < 0.) s = -s; } // Single precision functions namespace details { //------------------------------------------------------------------------------ /// Reduce to 0 to 45 inline float reduce2quadrant(float x, int & quad) { /* make argument positive */ x = fabs(x); quad = int (ONEOPIO4F * x); /* integer part of x/PIO4 */ quad = (quad+1) & (~1); const float y = float(quad); // quad &=4; // Extended precision modular arithmetic return ((x - y * DP1F) - y * DP2F) - y * DP3F; } //------------------------------------------------------------------------------ /// Sincos only for -45deg < x < 45deg inline void fast_sincosf_m45_45( const float x, float & s, float &c ) { float z = x * x; s = (((-1.9515295891E-4f * z + 8.3321608736E-3f) * z - 1.6666654611E-1f) * z * x) + x; c = (( 2.443315711809948E-005f * z - 1.388731625493765E-003f) * z + 4.166664568298827E-002f) * z * z - 0.5f * z + 1.0f; } //------------------------------------------------------------------------------ } // end details namespace /// Single precision sincos inline void fast_sincosf( const float xx, float & s, float &c ) { int j; const float x = details::reduce2quadrant(xx,j); int signS = (j&4); j-=2; const int signC = (j&4); const int poly = j&2; float ls,lc; details::fast_sincosf_m45_45(x,ls,lc); //swap if( poly==0 ) { const float tmp = lc; lc=ls; ls=tmp; } if(signC == 0) lc = -lc; if(signS != 0) ls = -ls; if (xx<0) ls = -ls; c=lc; s=ls; } } // end namespace vdt #endif