/* This file is part of the Vc library. {{{ Copyright (C) 2009-2012 Matthias Kretz Vc is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. Vc 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 General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with Vc. If not, see . }}}*/ /*includes {{{*/ #include "unittest.h" #include #include "vectormemoryhelper.h" #include "const.h" #include #include #include /*}}}*/ using namespace Vc; /*fix isfinite and isnan{{{*/ #ifdef isfinite #undef isfinite #endif #ifdef isnan #undef isnan #endif /*}}}*/ template struct SincosReference/*{{{*/ { T x, s, c; }; template struct Reference { T x, ref; }; template struct Array { size_t size; T *data; Array() : size(0), data(0) {} }; template struct StaticDeleter { T *ptr; StaticDeleter(T *p) : ptr(p) {} ~StaticDeleter() { delete[] ptr; } }; enum Function { Sincos, Atan, Asin, Acos, Log, Log2, Log10 }; template static inline const char *filename(); template<> inline const char *filename() { return "reference-sincos-sp.dat"; } template<> inline const char *filename() { return "reference-sincos-dp.dat"; } template<> inline const char *filename() { return "reference-atan-sp.dat"; } template<> inline const char *filename() { return "reference-atan-dp.dat"; } template<> inline const char *filename() { return "reference-asin-sp.dat"; } template<> inline const char *filename() { return "reference-asin-dp.dat"; } // template<> inline const char *filename() { return "reference-acos-sp.dat"; } // template<> inline const char *filename() { return "reference-acos-dp.dat"; } template<> inline const char *filename() { return "reference-ln-sp.dat"; } template<> inline const char *filename() { return "reference-ln-dp.dat"; } template<> inline const char *filename() { return "reference-log2-sp.dat"; } template<> inline const char *filename() { return "reference-log2-dp.dat"; } template<> inline const char *filename() { return "reference-log10-sp.dat"; } template<> inline const char *filename() { return "reference-log10-dp.dat"; } template static Array > sincosReference() { static Array > data; if (data.data == 0) { FILE *file = fopen(filename(), "rb"); if (file) { fseek(file, 0, SEEK_END); const size_t size = ftell(file) / sizeof(SincosReference); rewind(file); data.data = new SincosReference[size]; static StaticDeleter > _cleanup(data.data); data.size = fread(data.data, sizeof(SincosReference), size, file); fclose(file); } else { FAIL() << "the reference data " << filename() << " does not exist in the current working directory."; } } return data; } template static Array > referenceData() { static Array > data; if (data.data == 0) { FILE *file = fopen(filename(), "rb"); if (file) { fseek(file, 0, SEEK_END); const size_t size = ftell(file) / sizeof(Reference); rewind(file); data.data = new Reference[size]; static StaticDeleter > _cleanup(data.data); data.size = fread(data.data, sizeof(Reference), size, file); fclose(file); } else { FAIL() << "the reference data " << filename() << " does not exist in the current working directory."; } } return data; }/*}}}*/ template struct Denormals { static T *data; };/*{{{*/ template<> float *Denormals::data = 0; template<> double *Denormals::data = 0; enum { NDenormals = 64 }; /*}}}*/ template V apply_v(VC_ALIGNED_PARAMETER(V) x, typename V::EntryType (func)(typename V::EntryType))/*{{{*/ { V r; for (size_t i = 0; i < V::Size; ++i) { r[i] = func(x[i]); } return r; } /*}}}*/ template void testAbs()/*{{{*/ { for (int i = 0; i < 0x7fff; ++i) { Vec a(i); Vec b(-i); COMPARE(a, Vc::abs(a)); COMPARE(a, Vc::abs(b)); } } /*}}}*/ static inline float my_trunc(float x)/*{{{*/ { #if __cplusplus >= 201103 /*C++11*/ return std::trunc(x); #elif defined(_ISOC99_SOURCE) return truncf(x); #else return x > 0 ? std::floor(x) : std::ceil(x); #endif } static inline double my_trunc(double x) { #if __cplusplus >= 201103 /*C++11*/ return std::trunc(x); #elif defined(_ISOC99_SOURCE) return trunc(x); #else return x > 0 ? std::floor(x) : std::ceil(x); #endif } /*}}}*/ template void testTrunc()/*{{{*/ { typedef typename V::EntryType T; typedef typename V::IndexType I; for (size_t i = 0; i < 100000 / V::Size; ++i) { V x = (V::Random() - T(0.5)) * T(100); V reference = apply_v(x, my_trunc); COMPARE(Vc::trunc(x), reference) << ", x = " << x << ", i = " << i; } V x = static_cast(I::IndexesFromZero()); V reference = apply_v(x, my_trunc); COMPARE(Vc::trunc(x), reference) << ", x = " << x; } /*}}}*/ template void testFloor()/*{{{*/ { typedef typename V::EntryType T; typedef typename V::IndexType I; for (size_t i = 0; i < 100000 / V::Size; ++i) { V x = (V::Random() - T(0.5)) * T(100); V reference = apply_v(x, std::floor); COMPARE(Vc::floor(x), reference) << ", x = " << x << ", i = " << i; } V x = static_cast(I::IndexesFromZero()); V reference = apply_v(x, std::floor); COMPARE(Vc::floor(x), reference) << ", x = " << x; } /*}}}*/ template void testCeil()/*{{{*/ { typedef typename V::EntryType T; typedef typename V::IndexType I; for (size_t i = 0; i < 100000 / V::Size; ++i) { V x = (V::Random() - T(0.5)) * T(100); V reference = apply_v(x, std::ceil); COMPARE(Vc::ceil(x), reference) << ", x = " << x << ", i = " << i; } V x = static_cast(I::IndexesFromZero()); V reference = apply_v(x, std::ceil); COMPARE(Vc::ceil(x), reference) << ", x = " << x; } /*}}}*/ template void testExp()/*{{{*/ { setFuzzyness(1); setFuzzyness(2); typedef typename V::EntryType T; for (size_t i = 0; i < 100000 / V::Size; ++i) { V x = (V::Random() - T(0.5)) * T(20); V reference = apply_v(x, std::exp); FUZZY_COMPARE(Vc::exp(x), reference) << ", x = " << x << ", i = " << i; } COMPARE(Vc::exp(V::Zero()), V::One()); } /*}}}*/ template void testLog()/*{{{*/ { setFuzzyness(1); typedef typename V::EntryType T; Array > reference = referenceData(); for (size_t i = 0; i + V::Size - 1 < reference.size; i += V::Size) { V x, ref; for (int j = 0; j < V::Size; ++j) { x[j] = reference.data[i + j].x; ref[j] = reference.data[i + j].ref; } FUZZY_COMPARE(Vc::log(x), ref) << " x = " << x << ", i = " << i; } COMPARE(Vc::log(V::Zero()), V(std::log(T(0)))); for (int i = 0; i < NDenormals; i += V::Size) { V x(&Denormals::data[i]); V ref = apply_v(x, std::log); FUZZY_COMPARE(Vc::log(x), ref) << ", x = " << x << ", i = " << i; } } /*}}}*/ #if (defined(_XOPEN_SOURCE) && _XOPEN_SOURCE >= 600) || defined(_ISOC99_SOURCE) || (defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 200112L) static inline float my_log2(float x) { return ::log2f(x); } /* I need to make sure whether the log2 that I compare against is really precise to <0.5ulp. At * least I get different results when I use "double log2(double)", which is somewhat unexpected. * Well, conversion from double to float goes via truncation, so if the most significant truncated * mantissa bit is set the resulting float is incorrect by 1 ulp static inline float my_log2(float x) { return ::log2(static_cast(x)); } static inline float my_log2(float x) { double tmp = ::log2(static_cast(x)); int e; frexp(tmp, &e); // frexp(0.5) -> e = 0 return tmp + ldexp(tmp < 0 ? -0.5 : 0.5, e - 24); } */ static inline double my_log2(double x) { return ::log2(x); } #else static inline float my_log2(float x) { return ::logf(x) / Vc::Math::ln2(); } static inline double my_log2(double x) { return ::log(x) / Vc::Math::ln2(); } #endif /*}}}*/ template void testLog2()/*{{{*/ { #if defined(VC_LOG_ILP) || defined(VC_LOG_ILP2) setFuzzyness(3); #else setFuzzyness(1); #endif #if (defined(VC_MSVC) || defined(__APPLE__)) && defined(VC_IMPL_Scalar) setFuzzyness(2); #else setFuzzyness(1); #endif typedef typename V::EntryType T; Array > reference = referenceData(); for (size_t i = 0; i + V::Size - 1 < reference.size; i += V::Size) { V x, ref; for (int j = 0; j < V::Size; ++j) { x[j] = reference.data[i + j].x; ref[j] = reference.data[i + j].ref; } FUZZY_COMPARE(Vc::log2(x), ref) << " x = " << x << ", i = " << i; } COMPARE(Vc::log2(V::Zero()), V(my_log2(T(0)))); for (int i = 0; i < NDenormals; i += V::Size) { V x(&Denormals::data[i]); V ref = apply_v(x, my_log2); FUZZY_COMPARE(Vc::log2(x), ref) << ", x = " << x << ", i = " << i; } } /*}}}*/ template void testLog10()/*{{{*/ { setFuzzyness(2); setFuzzyness(2); typedef typename V::EntryType T; Array > reference = referenceData(); for (size_t i = 0; i + V::Size - 1 < reference.size; i += V::Size) { V x, ref; for (int j = 0; j < V::Size; ++j) { x[j] = reference.data[i + j].x; ref[j] = reference.data[i + j].ref; } FUZZY_COMPARE(Vc::log10(x), ref) << " x = " << x << ", i = " << i; } COMPARE(Vc::log10(V::Zero()), V(std::log10(T(0)))); for (int i = 0; i < NDenormals; i += V::Size) { V x(&Denormals::data[i]); V ref = apply_v(x, std::log10); FUZZY_COMPARE(Vc::log10(x), ref) << ", x = " << x << ", i = " << i; } } /*}}}*/ template void testMax()/*{{{*/ { typedef typename Vec::EntryType T; VectorMemoryHelper mem(3); T *data = mem; for (int i = 0; i < Vec::Size; ++i) { data[i] = i; data[i + Vec::Size] = Vec::Size + 1 - i; data[i + 2 * Vec::Size] = std::max(data[i], data[i + Vec::Size]); } Vec a(&data[0]); Vec b(&data[Vec::Size]); Vec c(&data[2 * Vec::Size]); COMPARE(Vc::max(a, b), c); } /*}}}*/ /*{{{*/ #define FillHelperMemory(code) \ typename V::Memory data; \ typename V::Memory reference; \ for (int ii = 0; ii < V::Size; ++ii) { \ const T i = static_cast(ii); \ data[ii] = i; \ reference[ii] = code; \ } do {} while (false) /*}}}*/ template void testSqrt()/*{{{*/ { typedef typename V::EntryType T; FillHelperMemory(std::sqrt(i)); V a(data); V b(reference); FUZZY_COMPARE(Vc::sqrt(a), b); } /*}}}*/ template void testRSqrt()/*{{{*/ { typedef typename V::EntryType T; for (size_t i = 0; i < 1024 / V::Size; ++i) { const V x = V::Random() * T(1000); // RSQRTPS is documented as having a relative error <= 1.5 * 2^-12 VERIFY(Vc::abs(Vc::rsqrt(x) * Vc::sqrt(x) - V::One()) < static_cast(std::ldexp(1.5, -12))); } } /*}}}*/ template void testSincos()/*{{{*/ { typedef typename V::EntryType T; setFuzzyness(2); setFuzzyness(1e7); Array > reference = sincosReference(); for (size_t i = 0; i + V::Size - 1 < reference.size; i += V::Size) { V x, sref, cref; for (int j = 0; j < V::Size; ++j) { x[j] = reference.data[i + j].x; sref[j] = reference.data[i + j].s; cref[j] = reference.data[i + j].c; } V sin, cos; Vc::sincos(x, &sin, &cos); FUZZY_COMPARE(sin, sref) << " x = " << x << ", i = " << i; FUZZY_COMPARE(cos, cref) << " x = " << x << ", i = " << i; Vc::sincos(-x, &sin, &cos); FUZZY_COMPARE(sin, -sref) << " x = " << -x << ", i = " << i; FUZZY_COMPARE(cos, cref) << " x = " << -x << ", i = " << i; } } /*}}}*/ template void testSin()/*{{{*/ { typedef typename V::EntryType T; setFuzzyness(2); setFuzzyness(1e7); Array > reference = sincosReference(); for (size_t i = 0; i + V::Size - 1 < reference.size; i += V::Size) { V x, sref; for (int j = 0; j < V::Size; ++j) { x[j] = reference.data[i + j].x; sref[j] = reference.data[i + j].s; } FUZZY_COMPARE(Vc::sin(x), sref) << " x = " << x << ", i = " << i; FUZZY_COMPARE(Vc::sin(-x), -sref) << " x = " << x << ", i = " << i; } } /*}}}*/ template void testCos()/*{{{*/ { typedef typename V::EntryType T; setFuzzyness(2); setFuzzyness(1e7); Array > reference = sincosReference(); for (size_t i = 0; i + V::Size - 1 < reference.size; i += V::Size) { V x, cref; for (int j = 0; j < V::Size; ++j) { x[j] = reference.data[i + j].x; cref[j] = reference.data[i + j].c; } FUZZY_COMPARE(Vc::cos(x), cref) << " x = " << x << ", i = " << i; FUZZY_COMPARE(Vc::cos(-x), cref) << " x = " << x << ", i = " << i; } } /*}}}*/ template void testAsin()/*{{{*/ { typedef typename V::EntryType T; setFuzzyness(2); setFuzzyness(36); Array > reference = referenceData(); for (size_t i = 0; i + V::Size - 1 < reference.size; i += V::Size) { V x, ref; for (int j = 0; j < V::Size; ++j) { x[j] = reference.data[i + j].x; ref[j] = reference.data[i + j].ref; } FUZZY_COMPARE(Vc::asin(x), ref) << " x = " << x << ", i = " << i; FUZZY_COMPARE(Vc::asin(-x), -ref) << " -x = " << -x << ", i = " << i; } } /*}}}*/ const union { unsigned int hex; float value; } INF = { 0x7f800000 }; #if defined(__APPLE__) && defined(VC_IMPL_Scalar) #define ATAN_COMPARE FUZZY_COMPARE #else #define ATAN_COMPARE COMPARE #endif template void testAtan()/*{{{*/ { typedef typename V::EntryType T; setFuzzyness(3); setFuzzyness(2); { const V Pi_2 = T(Vc_buildDouble(1, 0x921fb54442d18ull, 0)); V nan; nan.setQnan(); const V inf = T(INF.value); VERIFY(Vc::isnan(Vc::atan(nan))); ATAN_COMPARE(Vc::atan(+inf), +Pi_2); #ifdef VC_MSVC #pragma warning(suppress: 4756) // overflow in constant arithmetic #endif ATAN_COMPARE(Vc::atan(-inf), -Pi_2); } Array > reference = referenceData(); for (size_t i = 0; i + V::Size - 1 < reference.size; i += V::Size) { V x, ref; for (int j = 0; j < V::Size; ++j) { x[j] = reference.data[i + j].x; ref[j] = reference.data[i + j].ref; } FUZZY_COMPARE(Vc::atan(x), ref) << " x = " << x << ", i = " << i; FUZZY_COMPARE(Vc::atan(-x), -ref) << " -x = " << -x << ", i = " << i; } } /*}}}*/ template void testAtan2()/*{{{*/ { typedef typename V::EntryType T; setFuzzyness(3); setFuzzyness(2); { const V Pi = T(Vc_buildDouble(1, 0x921fb54442d18ull, 1)); const V Pi_2 = T(Vc_buildDouble(1, 0x921fb54442d18ull, 0)); V nan; nan.setQnan(); const V inf = T(INF.value); // If y is +0 (-0) and x is less than 0, +pi (-pi) is returned. ATAN_COMPARE(Vc::atan2(V(T(+0.)), V(T(-3.))), +Pi); ATAN_COMPARE(Vc::atan2(V(T(-0.)), V(T(-3.))), -Pi); // If y is +0 (-0) and x is greater than 0, +0 (-0) is returned. COMPARE(Vc::atan2(V(T(+0.)), V(T(+3.))), V(T(+0.))); VERIFY(!Vc::atan2(V(T(+0.)), V(T(+3.))).isNegative()); COMPARE(Vc::atan2(V(T(-0.)), V(T(+3.))), V(T(-0.))); VERIFY (Vc::atan2(V(T(-0.)), V(T(+3.))).isNegative()); // If y is less than 0 and x is +0 or -0, -pi/2 is returned. COMPARE(Vc::atan2(V(T(-3.)), V(T(+0.))), -Pi_2); COMPARE(Vc::atan2(V(T(-3.)), V(T(-0.))), -Pi_2); // If y is greater than 0 and x is +0 or -0, pi/2 is returned. COMPARE(Vc::atan2(V(T(+3.)), V(T(+0.))), +Pi_2); COMPARE(Vc::atan2(V(T(+3.)), V(T(-0.))), +Pi_2); // If either x or y is NaN, a NaN is returned. VERIFY(Vc::isnan(Vc::atan2(nan, V(T(3.))))); VERIFY(Vc::isnan(Vc::atan2(V(T(3.)), nan))); VERIFY(Vc::isnan(Vc::atan2(nan, nan))); // If y is +0 (-0) and x is -0, +pi (-pi) is returned. ATAN_COMPARE(Vc::atan2(V(T(+0.)), V(T(-0.))), +Pi); ATAN_COMPARE(Vc::atan2(V(T(-0.)), V(T(-0.))), -Pi); // If y is +0 (-0) and x is +0, +0 (-0) is returned. COMPARE(Vc::atan2(V(T(+0.)), V(T(+0.))), V(T(+0.))); COMPARE(Vc::atan2(V(T(-0.)), V(T(+0.))), V(T(-0.))); VERIFY(!Vc::atan2(V(T(+0.)), V(T(+0.))).isNegative()); VERIFY( Vc::atan2(V(T(-0.)), V(T(+0.))).isNegative()); // If y is a finite value greater (less) than 0, and x is negative infinity, +pi (-pi) is returned. ATAN_COMPARE(Vc::atan2(V(T(+1.)), -inf), +Pi); ATAN_COMPARE(Vc::atan2(V(T(-1.)), -inf), -Pi); // If y is a finite value greater (less) than 0, and x is positive infinity, +0 (-0) is returned. COMPARE(Vc::atan2(V(T(+3.)), +inf), V(T(+0.))); VERIFY(!Vc::atan2(V(T(+3.)), +inf).isNegative()); COMPARE(Vc::atan2(V(T(-3.)), +inf), V(T(-0.))); VERIFY (Vc::atan2(V(T(-3.)), +inf).isNegative()); // If y is positive infinity (negative infinity), and x is finite, pi/2 (-pi/2) is returned. COMPARE(Vc::atan2(+inf, V(T(+3.))), +Pi_2); COMPARE(Vc::atan2(-inf, V(T(+3.))), -Pi_2); COMPARE(Vc::atan2(+inf, V(T(-3.))), +Pi_2); COMPARE(Vc::atan2(-inf, V(T(-3.))), -Pi_2); #ifndef _WIN32 // the Microsoft implementation of atan2 fails this test const V Pi_4 = T(Vc_buildDouble(1, 0x921fb54442d18ull, -1)); // If y is positive infinity (negative infinity) and x is negative infinity, +3*pi/4 (-3*pi/4) is returned. COMPARE(Vc::atan2(+inf, -inf), T(+3.) * Pi_4); COMPARE(Vc::atan2(-inf, -inf), T(-3.) * Pi_4); // If y is positive infinity (negative infinity) and x is positive infinity, +pi/4 (-pi/4) is returned. COMPARE(Vc::atan2(+inf, +inf), +Pi_4); COMPARE(Vc::atan2(-inf, +inf), -Pi_4); #endif } for (int xoffset = -100; xoffset < 54613; xoffset += 47 * V::Size) { for (int yoffset = -100; yoffset < 54613; yoffset += 47 * V::Size) { FillHelperMemory(std::atan2((i + xoffset) * T(0.15), (i + yoffset) * T(0.15))); const V a(data); const V b(reference); const V x = (a + xoffset) * T(0.15); const V y = (a + yoffset) * T(0.15); FUZZY_COMPARE(Vc::atan2(x, y), b) << ", x = " << x << ", y = " << y; } } } /*}}}*/ template void testReciprocal()/*{{{*/ { typedef typename Vec::EntryType T; setFuzzyness(1.258295e+07); setFuzzyness(0); const T one = 1; for (int offset = -1000; offset < 1000; offset += 10) { const T scale = T(0.1); typename Vec::Memory data; typename Vec::Memory reference; for (int ii = 0; ii < Vec::Size; ++ii) { const T i = static_cast(ii); data[ii] = i; T tmp = (i + offset) * scale; reference[ii] = one / tmp; } Vec a(data); Vec b(reference); FUZZY_COMPARE(Vc::reciprocal((a + offset) * scale), b); } } /*}}}*/ template void isNegative()/*{{{*/ { typedef typename V::EntryType T; VERIFY(V::One().isNegative().isEmpty()); VERIFY(V::Zero().isNegative().isEmpty()); VERIFY((-V::One()).isNegative().isFull()); VERIFY(V(T(-0.)).isNegative().isFull()); } /*}}}*/ template void testInf()/*{{{*/ { typedef typename Vec::EntryType T; const T one = 1; const Vec zero(Zero); VERIFY(Vc::isfinite(zero)); VERIFY(Vc::isfinite(Vec(one))); VERIFY(!Vc::isfinite(one / zero)); } /*}}}*/ template void testNaN()/*{{{*/ { typedef typename Vec::EntryType T; typedef typename Vec::IndexType I; typedef typename Vec::Mask M; const T one = 1; const Vec zero(Zero); VERIFY(!Vc::isnan(zero)); VERIFY(!Vc::isnan(Vec(one))); const Vec inf = one / zero; VERIFY(Vc::isnan(Vec(inf * zero))); Vec nan = Vec::Zero(); const M mask(I::IndexesFromZero() == I::Zero()); nan.setQnan(mask); COMPARE(Vc::isnan(nan), mask); nan.setQnan(); VERIFY(Vc::isnan(nan)); } /*}}}*/ template void testRound()/*{{{*/ { typedef typename Vec::EntryType T; enum { Count = (16 + Vec::Size) / Vec::Size }; VectorMemoryHelper mem1(Count); VectorMemoryHelper mem2(Count); T *data = mem1; T *reference = mem2; for (int i = 0; i < Count * Vec::Size; ++i) { data[i] = i * 0.25 - 2.0; reference[i] = std::floor(i * 0.25 - 2.0 + 0.5); if (i % 8 == 2) { reference[i] -= 1.; } //std::cout << reference[i] << " "; } //std::cout << std::endl; for (int i = 0; i < Count; ++i) { const Vec a(&data[i * Vec::Size]); const Vec ref(&reference[i * Vec::Size]); //std::cout << a << ref << std::endl; COMPARE(Vc::round(a), ref); } } /*}}}*/ template void testReduceMin()/*{{{*/ { typedef typename Vec::EntryType T; const T one = 1; VectorMemoryHelper mem(Vec::Size); T *data = mem; for (int i = 0; i < Vec::Size * Vec::Size; ++i) { data[i] = i % (Vec::Size + 1) + one; } for (int i = 0; i < Vec::Size; ++i, data += Vec::Size) { const Vec a(&data[0]); //std::cout << a << std::endl; COMPARE(a.min(), one); } } /*}}}*/ template void testReduceMax()/*{{{*/ { typedef typename Vec::EntryType T; const T max = Vec::Size + 1; VectorMemoryHelper mem(Vec::Size); T *data = mem; for (int i = 0; i < Vec::Size * Vec::Size; ++i) { data[i] = (i + Vec::Size) % (Vec::Size + 1) + 1; } for (int i = 0; i < Vec::Size; ++i, data += Vec::Size) { const Vec a(&data[0]); //std::cout << a << std::endl; COMPARE(a.max(), max); } } /*}}}*/ template void testReduceProduct()/*{{{*/ { enum { Max = Vec::Size > 8 ? Vec::Size / 2 : Vec::Size }; typedef typename Vec::EntryType T; int _product = 1; for (int i = 1; i < Vec::Size; ++i) { _product *= (i % Max) + 1; } const T product = _product; VectorMemoryHelper mem(Vec::Size); T *data = mem; for (int i = 0; i < Vec::Size * Vec::Size; ++i) { data[i] = ((i + (i / Vec::Size)) % Max) + 1; } for (int i = 0; i < Vec::Size; ++i, data += Vec::Size) { const Vec a(&data[0]); //std::cout << a << std::endl; COMPARE(a.product(), product); } } /*}}}*/ template void testReduceSum()/*{{{*/ { typedef typename Vec::EntryType T; int _sum = 1; for (int i = 2; i <= Vec::Size; ++i) { _sum += i; } const T sum = _sum; VectorMemoryHelper mem(Vec::Size); T *data = mem; for (int i = 0; i < Vec::Size * Vec::Size; ++i) { data[i] = (i + i / Vec::Size) % Vec::Size + 1; } for (int i = 0; i < Vec::Size; ++i, data += Vec::Size) { const Vec a(&data[0]); //std::cout << a << std::endl; COMPARE(a.sum(), sum); } } /*}}}*/ template void testExponent()/*{{{*/ { typedef typename V::EntryType T; Vc::Memory input; Vc::Memory expected; input[ 0] = T(0.25); expected[ 0] = T(-2); input[ 1] = T( 1); expected[ 1] = T( 0); input[ 2] = T( 2); expected[ 2] = T( 1); input[ 3] = T( 3); expected[ 3] = T( 1); input[ 4] = T( 4); expected[ 4] = T( 2); input[ 5] = T( 0.5); expected[ 5] = T(-1); input[ 6] = T( 6); expected[ 6] = T( 2); input[ 7] = T( 7); expected[ 7] = T( 2); input[ 8] = T( 8); expected[ 8] = T( 3); input[ 9] = T( 9); expected[ 9] = T( 3); input[10] = T( 10); expected[10] = T( 3); input[11] = T( 11); expected[11] = T( 3); input[12] = T( 12); expected[12] = T( 3); input[13] = T( 13); expected[13] = T( 3); input[14] = T( 14); expected[14] = T( 3); input[15] = T( 15); expected[15] = T( 3); input[16] = T( 16); expected[16] = T( 4); input[17] = T( 17); expected[17] = T( 4); input[18] = T( 18); expected[18] = T( 4); input[19] = T( 19); expected[19] = T( 4); input[20] = T( 20); expected[20] = T( 4); input[21] = T( 21); expected[21] = T( 4); input[22] = T( 22); expected[22] = T( 4); input[23] = T( 23); expected[23] = T( 4); input[24] = T( 24); expected[24] = T( 4); input[25] = T( 25); expected[25] = T( 4); input[26] = T( 26); expected[26] = T( 4); input[27] = T( 27); expected[27] = T( 4); input[28] = T( 28); expected[28] = T( 4); input[29] = T( 29); expected[29] = T( 4); input[30] = T( 32); expected[30] = T( 5); input[31] = T( 31); expected[31] = T( 4); for (size_t i = 0; i < input.vectorsCount(); ++i) { COMPARE(V(input.vector(i)).exponent(), V(expected.vector(i))); } } /*}}}*/ template struct _ExponentVector { typedef int_v Type; }; template<> struct _ExponentVector { typedef short_v Type; }; template void testFrexp()/*{{{*/ { typedef typename V::EntryType T; typedef typename _ExponentVector::Type ExpV; Vc::Memory input; Vc::Memory expectedFraction; Vc::Memory expectedExponent; input[ 0] = T(0.25); expectedFraction[ 0] = T(.5 ); expectedExponent[ 0] = -1; input[ 1] = T( 1); expectedFraction[ 1] = T(.5 ); expectedExponent[ 1] = 1; input[ 2] = T( 0); expectedFraction[ 2] = T(0. ); expectedExponent[ 2] = 0; input[ 3] = T( 3); expectedFraction[ 3] = T(.75 ); expectedExponent[ 3] = 2; input[ 4] = T( 4); expectedFraction[ 4] = T(.5 ); expectedExponent[ 4] = 3; input[ 5] = T( 0.5); expectedFraction[ 5] = T(.5 ); expectedExponent[ 5] = 0; input[ 6] = T( 6); expectedFraction[ 6] = T( 6./8. ); expectedExponent[ 6] = 3; input[ 7] = T( 7); expectedFraction[ 7] = T( 7./8. ); expectedExponent[ 7] = 3; input[ 8] = T( 8); expectedFraction[ 8] = T( 8./16.); expectedExponent[ 8] = 4; input[ 9] = T( 9); expectedFraction[ 9] = T( 9./16.); expectedExponent[ 9] = 4; input[10] = T( 10); expectedFraction[10] = T(10./16.); expectedExponent[10] = 4; input[11] = T( 11); expectedFraction[11] = T(11./16.); expectedExponent[11] = 4; input[12] = T( 12); expectedFraction[12] = T(12./16.); expectedExponent[12] = 4; input[13] = T( 13); expectedFraction[13] = T(13./16.); expectedExponent[13] = 4; input[14] = T( 14); expectedFraction[14] = T(14./16.); expectedExponent[14] = 4; input[15] = T( 15); expectedFraction[15] = T(15./16.); expectedExponent[15] = 4; input[16] = T( 16); expectedFraction[16] = T(16./32.); expectedExponent[16] = 5; input[17] = T( 17); expectedFraction[17] = T(17./32.); expectedExponent[17] = 5; input[18] = T( 18); expectedFraction[18] = T(18./32.); expectedExponent[18] = 5; input[19] = T( 19); expectedFraction[19] = T(19./32.); expectedExponent[19] = 5; input[20] = T( 20); expectedFraction[20] = T(20./32.); expectedExponent[20] = 5; input[21] = T( 21); expectedFraction[21] = T(21./32.); expectedExponent[21] = 5; input[22] = T( 22); expectedFraction[22] = T(22./32.); expectedExponent[22] = 5; input[23] = T( 23); expectedFraction[23] = T(23./32.); expectedExponent[23] = 5; input[24] = T( 24); expectedFraction[24] = T(24./32.); expectedExponent[24] = 5; input[25] = T( 25); expectedFraction[25] = T(25./32.); expectedExponent[25] = 5; input[26] = T( 26); expectedFraction[26] = T(26./32.); expectedExponent[26] = 5; input[27] = T( 27); expectedFraction[27] = T(27./32.); expectedExponent[27] = 5; input[28] = T( 28); expectedFraction[28] = T(28./32.); expectedExponent[28] = 5; input[29] = T( 29); expectedFraction[29] = T(29./32.); expectedExponent[29] = 5; input[30] = T( 32); expectedFraction[30] = T(32./64.); expectedExponent[30] = 6; input[31] = T( 31); expectedFraction[31] = T(31./32.); expectedExponent[31] = 5; for (size_t i = 0; i < input.vectorsCount(); ++i) { const V v = input.vector(i); ExpV exp; COMPARE(frexp(v, &exp), V(expectedFraction.vector(i))); if (V::Size * 2 == ExpV::Size) { for (size_t j = 0; j < V::Size; ++j) { COMPARE(exp[j * 2], expectedExponent[i * V::Size + j]); } } else { COMPARE(exp, ExpV(expectedExponent.vector(i))); } } } /*}}}*/ template void testLdexp()/*{{{*/ { typedef typename V::EntryType T; typedef typename _ExponentVector::Type ExpV; for (size_t i = 0; i < 1024 / V::Size; ++i) { const V v = (V::Random() - T(0.5)) * T(1000); ExpV e; const V m = frexp(v, &e); COMPARE(ldexp(m, e), v) << ", m = " << m << ", e = " << e; } } /*}}}*/ #include "ulp.h" template void testUlpDiff()/*{{{*/ { typedef typename V::EntryType T; COMPARE(ulpDiffToReference(V::Zero(), V::Zero()), V::Zero()); COMPARE(ulpDiffToReference(std::numeric_limits::min(), V::Zero()), V::One()); COMPARE(ulpDiffToReference(V::Zero(), std::numeric_limits::min()), V::One()); for (size_t count = 0; count < 1024 / V::Size; ++count) { const V base = (V::Random() - T(0.5)) * T(1000); typename _Ulp_ExponentVector::Type exp; Vc::frexp(base, &exp); const V eps = ldexp(V(std::numeric_limits::epsilon()), exp - 1); //std::cout << base << ", " << exp << ", " << eps << std::endl; for (int i = -10000; i <= 10000; ++i) { const V i_v = V(T(i)); const V diff = base + i_v * eps; // if diff and base have a different exponent then ulpDiffToReference has an uncertainty // of +/-1 const V ulpDifference = ulpDiffToReference(diff, base); const V expectedDifference = Vc::abs(i_v); const V maxUncertainty = Vc::abs(abs(diff).exponent() - abs(base).exponent()); VERIFY(Vc::abs(ulpDifference - expectedDifference) <= maxUncertainty) << ", base = " << base << ", epsilon = " << eps << ", diff = " << diff; for (int k = 0; k < V::Size; ++k) { VERIFY(std::abs(ulpDifference[k] - expectedDifference[k]) <= maxUncertainty[k]); } } } }/*}}}*/ int main(int argc, char **argv)/*{{{*/ { initTest(argc, argv); Denormals::data = Vc::malloc(NDenormals);/*{{{*/ Denormals::data[0] = std::numeric_limits::denorm_min(); for (int i = 1; i < NDenormals; ++i) { Denormals::data[i] = Denormals::data[i - 1] * 2.173f; } Denormals::data = Vc::malloc(NDenormals); Denormals::data[0] = std::numeric_limits::denorm_min(); for (int i = 1; i < NDenormals; ++i) { Denormals::data[i] = Denormals::data[i - 1] * 2.173; }/*}}}*/ testRealTypes(isNegative); testRealTypes(testFrexp); testRealTypes(testLdexp); runTest(testAbs); runTest(testAbs); runTest(testAbs); runTest(testAbs); runTest(testAbs); testRealTypes(testUlpDiff); testRealTypes(testTrunc); testRealTypes(testFloor); testRealTypes(testCeil); testRealTypes(testExp); testRealTypes(testLog); testRealTypes(testLog2); testRealTypes(testLog10); runTest(testMax); runTest(testMax); runTest(testMax); runTest(testMax); runTest(testMax); runTest(testMax); runTest(testMax); testRealTypes(testSqrt); testRealTypes(testRSqrt); testRealTypes(testSin); testRealTypes(testCos); testRealTypes(testAsin); testRealTypes(testAtan); testRealTypes(testAtan2); testRealTypes(testReciprocal); testRealTypes(testInf); testRealTypes(testNaN); testRealTypes(testRound); runTest(testReduceMin); runTest(testReduceMin); runTest(testReduceMin); runTest(testReduceMin); runTest(testReduceMin); runTest(testReduceMin); runTest(testReduceMin); runTest(testReduceMax); runTest(testReduceMax); runTest(testReduceMax); runTest(testReduceMax); runTest(testReduceMax); runTest(testReduceMax); runTest(testReduceMax); runTest(testReduceProduct); runTest(testReduceProduct); runTest(testReduceProduct); runTest(testReduceProduct); runTest(testReduceProduct); runTest(testReduceProduct); runTest(testReduceProduct); runTest(testReduceSum); runTest(testReduceSum); runTest(testReduceSum); runTest(testReduceSum); runTest(testReduceSum); runTest(testReduceSum); runTest(testReduceSum); testRealTypes(testSincos); testRealTypes(testExponent); return 0; }/*}}}*/ // vim: foldmethod=marker