LCOV - code coverage report
Current view: top level - Utility - fmath.h (source / functions) Hit Total Coverage
Test: coverage.info.cleaned Lines: 58 58 100.0 %
Date: 2021-02-18 20:07:22 Functions: 8 8 100.0 %

          Line data    Source code
       1             : 
       2             : /**
       3             :         @brief fast math library for float
       4             :         @author herumi
       5             :         @url http://homepage1.nifty.com/herumi/
       6             :         @note modified new BSD license
       7             :         http://opensource.org/licenses/BSD-3-Clause
       8             :  
       9             :         cl /Ox /Ob2 /arch:SSE2 /fp:fast bench.cpp -I../xbyak /EHsc /DNOMINMAX
      10             :         g++ -O3 -fomit-frame-pointer -fno-operator-names -march=core2 -mssse3 -mfpmath=sse -ffast-math -fexcess-precision=fast
      11             :  */
      12             : /*
      13             :         function prototype list
      14             :  
      15             :         float fmath::exp(float);
      16             :         double fmath::expd(double);
      17             :         float fmath::log(float);
      18             :  
      19             :         __m128 fmath::exp_ps(__m128);
      20             :         __m256 fmath::exp_ps256(__m256);
      21             :         __m128 fmath::log_ps(__m128);
      22             :  
      23             :         double fmath::expd_v(double *, size_t n);
      24             :  
      25             :         if FMATH_USE_XBYAK is defined then Xbyak version are used
      26             :  */
      27             : 
      28             : #ifndef ATK_UTILITY_FMATH_H
      29             : #define ATK_UTILITY_FMATH_H
      30             : 
      31             : #include <algorithm>
      32             : #include <cmath>
      33             : #include <cstddef>
      34             : #include <cassert>
      35             : #include <limits>
      36             : #include <cstdint>
      37             : #include <cfloat>
      38             : #include <cstring> // for memcpy
      39             : 
      40             : #if defined(_WIN32) && !defined(__GNUC__)
      41             : # include <intrin.h>
      42             : # ifndef MIE_ALIGN
      43             : #  define MIE_ALIGN(x) __declspec(align(x))
      44             : # endif
      45             : #elif defined(__GNUC__) && (defined(__x86_64__) || defined(__i386__))
      46             : /* GCC >= 4.4 and non-GCC compilers */
      47             : # include <x86intrin.h>
      48             : #endif
      49             : #ifndef MIE_ALIGN
      50             : # define MIE_ALIGN(x) __attribute__((aligned(x)))
      51             : #endif
      52             : 
      53             : namespace fmath {
      54             :   
      55             :   namespace local {
      56             :     
      57             :     constexpr size_t EXP_TABLE_SIZE = 10;
      58             :     constexpr size_t EXPD_TABLE_SIZE = 11;
      59             :     constexpr size_t LOG_TABLE_SIZE = 12;
      60             :     
      61             :     union fi {
      62             :       float f;
      63             :       unsigned int i;
      64             :     };
      65             :     
      66             :     union di {
      67             :       double d;
      68             :       uint64_t i;
      69             :     };
      70             :     
      71    18043717 :     inline unsigned int mask(int x)
      72             :     {
      73    18043717 :       return (1U << x) - 1;
      74             :     }
      75             :     
      76      497664 :     inline uint64_t mask64(int x)
      77             :     {
      78      497664 :       return (1ULL << x) - 1;
      79             :     }
      80             :     
      81             :     template<class T>
      82             :     inline const T* cast_to(const void *p)
      83             :     {
      84             :       return reinterpret_cast<const T*>(p);
      85             :     }
      86             :     
      87             :     template<class T, size_t N>
      88             :     size_t NumOfArray(const T (&)[N]) { return N; }
      89             :     
      90             :     /*
      91             :      exp(88.722839F) = inf ; 0x42b17218
      92             :      exp(-87.33655F) = 1.175491e-038f(007fffe6) denormal ; 0xc2aeac50
      93             :      exp(-103.972081F) = 0 ; 0xc2cff1b5
      94             :      */
      95             :     template<size_t N = EXP_TABLE_SIZE>
      96             :     class ExpVar {
      97             :     public:
      98             :       enum {
      99             :         s = N,
     100             :         n = 1 << s,
     101             :         f88 = 0x42b00000 /* 88.0 */
     102             :       };
     103             :       float minX[8];
     104             :       float maxX[8];
     105             :       float a[8];
     106             :       float b[8];
     107             :       float f1[8];
     108             :       unsigned int i127s[8];
     109             :       unsigned int mask_s[8];
     110             :       unsigned int i7fffffff[8];
     111             :       unsigned int tbl[n];
     112             :       ExpVar()
     113             :       {
     114             :         float log_2 = std::log(2.0F);
     115             :         for (int i = 0; i < 8; i++) {
     116             :           maxX[i] = 88;
     117             :           minX[i] = -88;
     118             :           a[i] = n / log_2;
     119             :           b[i] = log_2 / n;
     120             :           f1[i] = 1.0F;
     121             :           i127s[i] = 127 << s;
     122             :           i7fffffff[i] = 0x7fffffff;
     123             :           mask_s[i] = mask(s);
     124             :         }
     125             :         
     126             :         for (int i = 0; i < n; i++) {
     127             :           float y = std::pow(2.0F, static_cast<float>(i) / n);
     128             :           fi fi;
     129             :           fi.f = y;
     130             :           tbl[i] = fi.i & mask(23);
     131             :         }
     132             :       }
     133             :     };
     134             :     
     135             :     template<size_t sbit_ = EXPD_TABLE_SIZE>
     136             :     class ExpdVar {
     137             :     public:
     138             :       enum {
     139             :         sbit = sbit_,
     140             :         s = 1UL << sbit,
     141             :         adj = (1UL << (sbit + 10)) - (1UL << sbit)
     142             :       };
     143             :       // A = 1, B = 1, C = 1/2, D = 1/6
     144             :       double C1[2]{}; // A
     145             :       double C2[2]{}; // D
     146             :       double C3[2]{}; // C/D
     147             :       uint64_t tbl[s]{};
     148             :       double a{};
     149             :       double ra{};
     150         243 :       ExpdVar()
     151             :       : a(s / ::log(2.0))
     152         243 :       , ra(1 / a)
     153             :       {
     154         729 :         for (int i = 0; i < 2; i++) {
     155         486 :           C1[i] = 1.0;
     156         486 :           C2[i] = 0.16666666685227835064;
     157         486 :           C3[i] = 3.0000000027955394;
     158             :         }
     159      497907 :         for (int i = 0; i < s; i++) {
     160             :           di di;
     161      497664 :           di.d = ::pow(2.0, i * (1.0 / s));
     162      497664 :           tbl[i] = di.i & mask64(52);
     163             :         }
     164         243 :       }
     165             :     };
     166             :     
     167             :     template<size_t N = LOG_TABLE_SIZE>
     168             :     class LogVar {
     169             :     public:
     170             :       enum {
     171             :         LEN = N - 1
     172             :       };
     173             :       unsigned int m1[4]; // 0
     174             :       unsigned int m2[4]; // 16
     175             :       unsigned int m3[4]; // 32
     176             :       float m4[4];              // 48
     177             :       unsigned int m5[4]; // 64
     178             :       struct {
     179             :         float app;
     180             :         float rev;
     181             :       } tbl[1 << LEN];
     182             :       float c_log2;
     183         243 :       LogVar()
     184         243 :       : c_log2(std::log(2.0F) / (1 << 23))
     185             :       {
     186         243 :         const double e = 1 / static_cast<double>(1 << 24);
     187         243 :         const double h = 1 / static_cast<double>(1 << LEN);
     188         243 :         constexpr size_t n = 1U << LEN;
     189      497907 :         for (size_t i = 0; i < n; i++) {
     190      497664 :           double x = 1 + static_cast<double>(i) / n;
     191      497664 :           double a = std::log(x);
     192      497664 :           tbl[i].app = static_cast<float>(a);
     193      497664 :           if (i < n - 1) {
     194      497421 :             double b = std::log(x + h - e);
     195      497421 :             tbl[i].rev = static_cast<float>((b - a) / ((h - e) * (1 << 23)));
     196             :           } else {
     197         243 :             tbl[i].rev = static_cast<float>(1 / (x * (1 << 23)));
     198             :           }
     199             :         }
     200        1215 :         for (int i = 0; i < 4; i++) {
     201         972 :           m1[i] = mask(8) << 23;
     202         972 :           m2[i] = mask(LEN) << (23 - LEN);
     203         972 :           m3[i] = mask(23 - LEN);
     204         972 :           m4[i] = c_log2;
     205         972 :           m5[i] = 127U << 23;
     206             :         }
     207         243 :       }
     208             :     };
     209             :     /* to define static variables in fmath.hpp */
     210             :     template<size_t EXP_N = EXP_TABLE_SIZE, size_t LOG_N = LOG_TABLE_SIZE, size_t EXPD_N = EXPD_TABLE_SIZE>
     211             :     struct C {
     212             :       static const ExpVar<EXP_N> expVar;
     213             :       static const LogVar<LOG_N> logVar;
     214             :       static const ExpdVar<EXPD_N> expdVar;
     215             :     };
     216             :     
     217             :     template<size_t EXP_N, size_t LOG_N, size_t EXPD_N>
     218             :     MIE_ALIGN(32) const ExpVar<EXP_N> C<EXP_N, LOG_N, EXPD_N>::expVar;
     219             :     
     220             :     template<size_t EXP_N, size_t LOG_N, size_t EXPD_N>
     221             :     MIE_ALIGN(32) const LogVar<LOG_N> C<EXP_N, LOG_N, EXPD_N>::logVar;
     222             :     
     223             :     template<size_t EXP_N, size_t LOG_N, size_t EXPD_N>
     224             :     MIE_ALIGN(32) const ExpdVar<EXPD_N> C<EXP_N, LOG_N, EXPD_N>::expdVar;
     225             :     
     226             :   } // fmath::local
     227             :   
     228             : #if defined(ATK_NO_FMATH) || defined(__GNUC__) && !(defined(__x86_64__) || defined(__i386__))
     229             :   using std::exp;
     230             :   using std::log;
     231             : #else
     232    21459496 :   inline double exp(double x)
     233             :   {
     234    21459496 :     if (x <= -708.39641853226408)
     235             :     {
     236     3025571 :       return 0;
     237             :     }
     238    18433945 :     if (x >= 709.78271289338397)
     239             :     {
     240      393215 :       return std::numeric_limits<double>::infinity();
     241             :     }
     242             : 
     243    18040745 :     const auto& c = local::C<>::expdVar;
     244    18040745 :     const double _b = static_cast<double>(uint64_t(3) << 51);
     245    18040745 :     __m128d b = _mm_load_sd(&_b);
     246    18040745 :     __m128d xx = _mm_load_sd(&x);
     247    72162882 :     __m128d d = _mm_add_sd(_mm_mul_sd(xx, _mm_load_sd(&c.a)), b);
     248    18040745 :     uint64_t di = _mm_cvtsi128_si32(_mm_castpd_si128(d));
     249    18040745 :     uint64_t iax = c.tbl[di & mask(c.sbit)];
     250    72163282 :     __m128d _t = _mm_sub_sd(_mm_mul_sd(_mm_sub_sd(d, b), _mm_load_sd(&c.ra)), xx);
     251    18040845 :     uint64_t u = ((di + c.adj) >> c.sbit) << 52;
     252             :     double t;
     253             :     _mm_store_sd(&t, _t);
     254    18040845 :     double y = (c.C3[0] - t) * (t * t) * c.C2[0] - t + c.C1[0];
     255             :     double did;
     256    18040845 :     u |= iax;
     257    18040845 :     memcpy(&did, &u, sizeof(did));
     258    18040845 :     return y * did;
     259             :   }
     260             : 
     261             :   inline float exp(float x)
     262             :   {
     263             :     return static_cast<float>(exp(static_cast<double>(x)));
     264             :   }
     265             : 
     266             :   inline float log(float x)
     267             :   {
     268             :     const auto& logVar = local::C<>::logVar;
     269             :     constexpr size_t logLen = logVar.LEN;
     270             :     
     271             :     local::fi fi;
     272             :     fi.f = x;
     273             :     int a = fi.i & (local::mask(8) << 23);
     274             :     unsigned int b1 = fi.i & (local::mask(logLen) << (23 - logLen));
     275             :     unsigned int b2 = fi.i & local::mask(23 - logLen);
     276             :     int idx = b1 >> (23 - logLen);
     277             :     float f = static_cast<float>(a - (127 << 23)) * logVar.c_log2 + logVar.tbl[idx].app + static_cast<float>(b2) * logVar.tbl[idx].rev;
     278             :     return f;
     279             :   }
     280             :   
     281             :   inline float log2(float x) { return fmath::log(x) * 1.442695F; }
     282             : 
     283    40206489 :   inline double log(double x)
     284             :   {
     285    40206489 :     return std::log(x);
     286             :   }
     287             : #endif
     288             : 
     289    16432752 :   inline double pow(double x, double y)
     290             :   {
     291    16432752 :     return exp(y * fmath::log(x));
     292             :   }
     293             : 
     294             :   inline float pow(float x, float y)
     295             :   {
     296             :     return exp(y * fmath::log(x));
     297             :   }
     298             : 
     299             :   template<typename T>
     300    11799100 :   T log10(T x)
     301             :   {
     302    11799100 :     return log(x) / log(static_cast<T>(10));
     303             :   }
     304             : 
     305             :   /*
     306             :    for given y > 0
     307             :    get f_y(x) := pow(x, y) for x >= 0
     308             :    */
     309             :   class PowGenerator {
     310             :     enum {
     311             :       N = 11
     312             :     };
     313             :     float tbl0_[256]{};
     314             :     struct {
     315             :       float app;
     316             :       float rev;
     317             :     } tbl1_[1 << N]{};
     318             :   public:
     319             :     explicit PowGenerator(float y)
     320             :     {
     321             :       for (int i = 0; i < 256; i++) {
     322             :         tbl0_[i] = static_cast<float>(std::pow(2, (i - 127) * y));
     323             :       }
     324             :       const double e = 1 / static_cast<double>(1 << 24);
     325             :       const double h = 1 / static_cast<double>(1 << N);
     326             :       constexpr size_t n = 1U << N;
     327             :       for (size_t i = 0; i < n; i++) {
     328             :         double x = 1 + static_cast<double>(i) / n;
     329             :         double a = std::pow(x, static_cast<double>(y));
     330             :         tbl1_[i].app = static_cast<float>(a);
     331             :         double b = std::pow(x + h - e, static_cast<double>(y));
     332             :         tbl1_[i].rev = static_cast<float>((b - a) / (h - e) / (1 << 23));
     333             :       }
     334             :     }
     335             :     float get(float x) const
     336             :     {
     337             :       local::fi fi;
     338             :       fi.f = x;
     339             :       int a = (fi.i >> 23) & local::mask(8);
     340             :       unsigned int b = fi.i & local::mask(23);
     341             :       unsigned int b1 = b & (local::mask(N) << (23 - N));
     342             :       unsigned int b2 = b & local::mask(23 - N);
     343             :       float f;
     344             :       int idx = b1 >> (23 - N);
     345             :       f = tbl0_[a] * (tbl1_[idx].app + static_cast<float>(b2) * tbl1_[idx].rev);
     346             :       return f;
     347             :     }
     348             :   };
     349             :   
     350             :   // exp2(x) = pow(2, x)
     351             :   inline float exp2(float x) { return fmath::exp(x * 0.6931472F); }
     352             :   
     353             : } // fmath
     354             : 
     355             : #endif

Generated by: LCOV version TK-3.3.0-4-gdba42eea