/
githubmirror
/
cmssw
Обзор
Документация
Войти
/
githubmirror
/
cmssw
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
master
DataFormats/Math/test/testApproxMath.cpp
243 строки
7 KB
Cms Build
Clang-Format
11 июн 2019, 11:29
11 июн 2019, 11:29
146bc98
Код
Авторство
О чём код?
#include "DataFormats/Math/interface/approx_exp.h" #include "DataFormats/Math/interface/approx_log.h" #include "DataFormats/Math/interface/approx_erf.h" #include <cstdio> #include <cstdlib> #include <iostream> void printEXP(float x) { printf("x= %a val= %a %a %a\n", x, std::exp(double(x)), unsafe_expf<6>(x), unsafe_expf<4>(x)); printf("x= %f val= %f %f %f\n", x, std::exp(double(x)), unsafe_expf<6>(x), unsafe_expf<4>(x)); printf("x= %f val= %f %f %f\n\n", x, std::exp(x), approx_expf<6>(x), approx_expf<4>(x)); } void printLOG(float x) { printf("x= %a val= %a %a %a\n", x, std::log(double(x)), unsafe_logf<8>(x), unsafe_logf<4>(x)); printf("x= %f val= %f %f %f\n", x, std::log(double(x)), unsafe_logf<8>(x), unsafe_logf<4>(x)); printf("x= %f val= %f %f %f\n\n", x, std::log(x), approx_logf<6>(x), approx_logf<4>(x)); } template <typename PRINT> void printLim(PRINT printit) { constexpr float zero_threshold_ftz = -float(0x5.75628p4); constexpr float inf_threshold = float(0x5.8b90cp4); std::cout << "\nexp valid for " << zero_threshold_ftz << " < x < " << inf_threshold << std::endl; printit(zero_threshold_ftz); printit(zero_threshold_ftz - 1); printit(zero_threshold_ftz + 1); printit(4 * zero_threshold_ftz); printit(0); printit(1.); printit(-1.); printit(inf_threshold); printit(inf_threshold + 1); printit(inf_threshold - 1); printit(4 * inf_threshold); printit(std::sqrt(-1)); printit(std::numeric_limits<float>::infinity()); printit(-std::numeric_limits<float>::infinity()); std::cout << "\n" << std::endl; } namespace justcomp { constexpr int NN = 1024 * 1024; float a[NN], b[NN]; template <int DEGREE> void bar() { for (int i = 0; i != NN; ++i) b[i] = approx_expf<DEGREE>(a[i]); } template <int DEGREE> void foo() { for (int i = 0; i != NN; ++i) b[i] = unsafe_expf<DEGREE>(a[i]); } template <int DEGREE> void lar() { for (int i = 0; i != NN; ++i) b[i] = approx_logf<DEGREE>(a[i]); } template <int DEGREE> void loo() { for (int i = 0; i != NN; ++i) b[i] = unsafe_logf<DEGREE>(a[i]); } } // namespace justcomp template <typename STD, typename APPROX> void accTest(STD stdf, APPROX approx, int degree) { using namespace approx_math; std::cout << std::endl << "launching exhaustive test for degree " << degree << std::endl; binary32 x, r, ref; int maxdiff = 0; int n127 = 0; int n16393 = 0; x.ui32 = 0; // should be 0 but while (x.ui32 < 0xffffffff) { x.ui32++; // remove nans.. if ((x.ui32 & 0x7f80000) && x.ui32 & 0x7FFFFF) continue; r.f = approx(x.f); ref.f = stdf(double(x.f)); // double-prec one (no hope with -fno-math-errno) int d = abs(r.i32 - ref.i32); if (d > maxdiff) { // std::cout << "new maxdiff for x=" << x.f << " : " << d << std::endl; maxdiff = d; } if (d > 127) ++n127; if (d > 16393) ++n16393; } std::cout << "maxdiff / diff >127 / diff >16393 " << maxdiff << " / " << n127 << " / " << n16393 << std::endl; } template <typename STD, typename APPROX> void accuTest(STD stdf, APPROX approx, const char* name, float mm = std::numeric_limits<float>::min(), float mx = std::numeric_limits<float>::max()) { using namespace approx_math; std::cout << std::endl << "launching exhaustive test for " << name << std::endl; binary32 x, pend, r, ref; int maxdiff = 0; int n127 = 0; int n16393 = 0; float ad = 0., rd = 0; x.f = mm; x.ui32++; pend.f = mx; pend.ui32--; std::cout << "limits " << x.f << " " << pend.f << " " << pend.ui32 - x.ui32 << std::endl; while (x.ui32 < pend.ui32) { x.ui32++; r.f = approx(x.f); ref.f = stdf(x.f); // double-prec one (no hope with -fno-math-errno) ad = std::max(ad, std::abs(r.f - ref.f)); rd = std::max(rd, std::abs((r.f / ref.f) - 1.f)); int d = abs(r.i32 - ref.i32); if (d > maxdiff) { // std::cout << "new maxdiff for x=" << x.f << " : " << d << std::endl; maxdiff = d; } if (d > 127) ++n127; if (d > 16393) ++n16393; } std::cout << "absdiff / reldeff/ maxdiff / diff >127 / diff >16393 : " << ad << " / " << rd << " / " << maxdiff << " / " << n127 << " / " << n16393 << std::endl; } // performance test #include "rdtscp.h" template <int DEGREE, int WHAT> struct Measure { inline void operator()(unsigned long long& t) const; }; template <int DEGREE> struct Measure<DEGREE, 0> { inline void operator()(unsigned long long& t) const { t -= rdtsc(); justcomp::foo<DEGREE>(); t += rdtsc(); } }; template <int DEGREE> struct Measure<DEGREE, 1> { inline void operator()(unsigned long long& t) const { t -= rdtsc(); justcomp::bar<DEGREE>(); t += rdtsc(); } }; template <int DEGREE> struct Measure<DEGREE, 2> { inline void operator()(unsigned long long& t) const { t -= rdtsc(); justcomp::loo<DEGREE>(); t += rdtsc(); } }; template <int DEGREE> struct Measure<DEGREE, 3> { inline void operator()(unsigned long long& t) const { t -= rdtsc(); justcomp::lar<DEGREE>(); t += rdtsc(); } }; template <int DEGREE, int WHAT = 1> void perf() { if (!has_rdtscp()) return; Measure<DEGREE, WHAT> measure; using namespace approx_math; unsigned long long t = 0; binary32 x; float sum = 0; long long ntot = 0; x.f = 1.0; // should be 0 but while (x.f < 32) { // this is 5*2^23 tests ++ntot; int i = 0; while (i < justcomp::NN) { x.ui32++; justcomp::a[i++] = x.f; justcomp::a[i++] = (WHAT < 2) ? -x.f : 1.f / x.f; } measure(t); // binary32 r; // r.f=approx_expf<6>(x.f);// time 0m1.180s // r.f=expf(x.f); // time 0m4.372s // r.f=exp(x.f); // time 0m1.789s for (int i = 0; i != justcomp::NN; ++i) sum += justcomp::b[i]; } const char* what[] = {"exp unsafe", "exp apporx", "log unsafe", "log approx"}; std::cout << "time for " << what[WHAT] << " degree " << DEGREE << " is " << double(t) / double(justcomp::NN * ntot) << std::endl; std::cout << "sum= " << sum << " to prevent compiler optim." << std::endl; ; } int main() { printLim(printEXP); printLim(printLOG); perf<2, 0>(); perf<3, 0>(); perf<3>(); perf<4>(); perf<6>(); perf<2, 2>(); perf<2, 3>(); perf<4, 2>(); perf<4, 3>(); perf<8, 2>(); perf<8, 3>(); accTest(::exp, approx_expf<2>, 2); accTest(::exp, approx_expf<3>, 3); accTest(::exp, approx_expf<4>, 4); accTest(::exp, approx_expf<6>, 6); accTest(::log, approx_logf<2>, 2); accTest(::log, approx_logf<4>, 4); accTest(::log, approx_logf<8>, 8); accuTest(::erf, approx_erf, "erf", .01, 8); return 0; }