summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorRJ Ryan <rryan@mixxx.org>2015-12-13 11:17:31 -0800
committerRJ Ryan <rryan@mixxx.org>2015-12-13 11:17:31 -0800
commit451cd0c89f44bdd3abb4ff14573213aa48e874c6 (patch)
tree8f3d2f47a47e0c0cb96c3e822879a07ade8c8929 /src
parenta883747bc107d0052135c77c3a4b4a0bff255001 (diff)
parenta1db003962c0f61a2cfa3c3ae97235ba77031d2e (diff)
Merge pull request #807 from daschuer/fpclassify
fpclassify wrapper
Diffstat (limited to 'src')
-rw-r--r--src/test/mathutiltest.cpp54
-rw-r--r--src/util/fpclassify.cpp46
-rw-r--r--src/util/fpclassify.h38
-rw-r--r--src/util/math.h13
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) {