diff options
author | RJ Ryan <rryan@mixxx.org> | 2015-12-13 11:17:31 -0800 |
---|---|---|
committer | RJ Ryan <rryan@mixxx.org> | 2015-12-13 11:17:31 -0800 |
commit | 451cd0c89f44bdd3abb4ff14573213aa48e874c6 (patch) | |
tree | 8f3d2f47a47e0c0cb96c3e822879a07ade8c8929 /src | |
parent | a883747bc107d0052135c77c3a4b4a0bff255001 (diff) | |
parent | a1db003962c0f61a2cfa3c3ae97235ba77031d2e (diff) |
Merge pull request #807 from daschuer/fpclassify
fpclassify wrapper
Diffstat (limited to 'src')
-rw-r--r-- | src/test/mathutiltest.cpp | 54 | ||||
-rw-r--r-- | src/util/fpclassify.cpp | 46 | ||||
-rw-r--r-- | src/util/fpclassify.h | 38 | ||||
-rw-r--r-- | src/util/math.h | 13 |
4 files changed, 136 insertions, 15 deletions
diff --git a/src/test/mathutiltest.cpp b/src/test/mathutiltest.cpp index 847472671e..9d0be9ca9e 100644 --- a/src/test/mathutiltest.cpp +++ b/src/test/mathutiltest.cpp @@ -1,8 +1,11 @@ -#include <gtest/gtest.h> -#include "util/math.h" +#include <limits> +#include <gtest/gtest.h> #include <QtDebug> +#include "util/math.h" +#include "util/denormalsarezero.h" + namespace { class MathUtilTest : public testing::Test { @@ -28,7 +31,7 @@ const int MathUtilTest::MIN = -10; const int MathUtilTest::MAX = 10; const int MathUtilTest::VALUE_MIN = 2 * MathUtilTest::MIN; -const int MathUtilTest::VALUE_MAX = 2 * MathUtilTest::MAX; +const int MathUtilTest::VALUE_MAX = 2 * MathUtilTest::MAX; TEST_F(MathUtilTest, MathClampUnsafe) { for (int i = VALUE_MIN; i <= VALUE_MAX; ++i) { @@ -45,4 +48,49 @@ TEST_F(MathUtilTest, MathClampUnsafe) { } } +TEST_F(MathUtilTest, IsNaN) { + // Test floats can be recognized as nan. + EXPECT_FALSE(isnan(0.0f)); + EXPECT_TRUE(isnan(std::numeric_limits<float>::quiet_NaN())); + + // Test doubles can be recognized as nan. + EXPECT_FALSE(isnan(0.0)); + EXPECT_TRUE(isnan(std::numeric_limits<double>::quiet_NaN())); +} + +TEST_F(MathUtilTest, IsInf) { + // Test floats can be recognized as infinity. + EXPECT_FALSE(isinf(0.0f)); + EXPECT_TRUE(isinf(std::numeric_limits<float>::infinity())); + + // Test doubles can be recognized as infinity. + EXPECT_FALSE(isinf(0.0f)); + EXPECT_TRUE(isinf(std::numeric_limits<double>::infinity())); +} + +TEST_F(MathUtilTest, Denormal) { +#ifdef __SSE__ + + _MM_SET_DENORMALS_ZERO_MODE(_MM_DENORMALS_ZERO_OFF); + _MM_SET_FLUSH_ZERO_MODE(_MM_FLUSH_ZERO_OFF); + + volatile float fDenormal = std::numeric_limits<float>::min() / 2.0f; + EXPECT_NE(0.0f, fDenormal); + + volatile double dDenormal = std::numeric_limits<double>::min() / 2.0; + EXPECT_NE(0.0, dDenormal); + + _MM_SET_DENORMALS_ZERO_MODE(_MM_DENORMALS_ZERO_ON); + _MM_SET_FLUSH_ZERO_MODE(_MM_FLUSH_ZERO_ON); + + fDenormal = std::numeric_limits<float>::min() / 2.0f; + EXPECT_EQ(0.0f, fDenormal); + + dDenormal = std::numeric_limits<double>::min() / 2.0; + EXPECT_EQ(0.0, dDenormal); + +#endif +} + + } // namespace diff --git a/src/util/fpclassify.cpp b/src/util/fpclassify.cpp new file mode 100644 index 0000000000..2135d8a771 --- /dev/null +++ b/src/util/fpclassify.cpp @@ -0,0 +1,46 @@ +// this is a wapper around the fpclassify functions which prevents inlining +// It is compiled without optization +// The rest of the source of Mixxx is compiled with -ffast-math, which breaks +// the fpclassify functions + +#include <cmath> + +int util_fpclassify(float x) { + return std::fpclassify(x); +} + +int util_isfinite(float x) { + return std::isfinite(x); +} + +int util_isnormal(float x) { + return std::isnormal(x); +} + +int util_isnan(float x) { + return std::isnan(x); +} + +int util_isinf(float x) { + return std::isinf(x); +} + +int util_fpclassify(double x) { + return std::fpclassify(x); +} + +int util_isfinite(double x) { + return std::isfinite(x); +} + +int util_isnormal(double x) { + return std::isnormal(x); +} + +int util_isnan(double x) { + return std::isnan(x); +} + +int util_isinf(double x) { + return std::isinf(x); +} diff --git a/src/util/fpclassify.h b/src/util/fpclassify.h new file mode 100644 index 0000000000..c1df4fdedd --- /dev/null +++ b/src/util/fpclassify.h @@ -0,0 +1,38 @@ +#ifndef UTIL_FPCLASSIFY_H +#define UTIL_FPCLASSIFY_H + +#ifdef _MSC_VER + +// VC++ uses _isnan() instead of isnan() and !_finite instead of isinf. +#include <float.h> +#define isnan(x) _isnan(x) +#define isinf(x) (!_finite(x)) + +#else + +// We define +// these as macros to prevent clashing with c++11 built-ins in the global +// namespace. If you say "using std::isnan;" then this will fail to build with +// std=c++11. See https://bugs.webkit.org/show_bug.cgi?id=59249 for some +// relevant discussion. + +#define isnan util_isnan +#define isinf util_isinf +#define isnormal util_isnormal +#define fpclassify util_fpclassify +#define isfinite util_isfinite + +int util_fpclassify(float x); +int util_isfinite(float x); +int util_isnormal(float x); +int util_isnan(float x); +int util_isinf(float x); +int util_fpclassify(double x); +int util_isfinite(double x); +int util_isnormal(double x); +int util_isnan(double x); +int util_isinf(double x); + +#endif + +#endif // UTIL_FPCLASSIFY_H diff --git a/src/util/math.h b/src/util/math.h index 82afe19696..018335e4fc 100644 --- a/src/util/math.h +++ b/src/util/math.h @@ -8,6 +8,7 @@ #include <algorithm> #include "util/assert.h" +#include "util/fpclassify.h" // If we don't do this then we get the C90 fabs from the global namespace which // is only defined for double. @@ -35,20 +36,8 @@ inline bool even(T value) { } #ifdef _MSC_VER -// VC++ uses _isnan() instead of isnan() and !_finite instead of isinf. -#include <float.h> -#define isnan(x) _isnan(x) -#define isinf(x) (!_finite(x)) // Ask VC++ to emit an intrinsic for fabs instead of calling std::fabs. #pragma intrinsic(fabs) -#else -// for isnan() and isinf() everywhere else use the cmath version. We define -// these as macros to prevent clashing with c++11 built-ins in the global -// namespace. If you say "using std::isnan;" then this will fail to build with -// std=c++11. See https://bugs.webkit.org/show_bug.cgi?id=59249 for some -// relevant discussion. -#define isnan std::isnan -#define isinf std::isinf #endif inline int roundUpToPowerOf2(int v) { |