summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEdward Welbourne <edward.welbourne@qt.io>2019-03-13 18:49:04 +0100
committerEdward Welbourne <edward.welbourne@qt.io>2019-03-19 17:52:30 +0000
commit84aea6c091d020a37c2b452a6f56ca27b3b2c7cb (patch)
tree50f321ea52344cfd3831856aabf44089b4962094
parent368eb2ecec7cc54ea987de00df7caa52a0d4503a (diff)
Add qFpClassify() to mirror std::fpclassify()
The rules of std don't permit us to add an overload for fpclassify(qfloat16), so we need our own equivalent that we *can* overload. Deploy it in the few places we use fpclassify(). Extended qnumeric's testing to cover qFpClassify(). Change-Id: Ie5a0a5cc24599d1571404c573d33c682b0d305a5 Reviewed-by: Thiago Macieira <thiago.macieira@intel.com> Reviewed-by: Paul Wicking <paul.wicking@qt.io>
-rw-r--r--src/corelib/global/qnumeric.cpp25
-rw-r--r--src/corelib/global/qnumeric.h4
-rw-r--r--src/corelib/global/qnumeric_p.h19
-rw-r--r--src/corelib/kernel/qvariant.cpp6
-rw-r--r--src/testlib/qtestcase.cpp10
-rw-r--r--tests/auto/corelib/global/qnumeric/tst_qnumeric.cpp32
6 files changed, 84 insertions, 12 deletions
diff --git a/src/corelib/global/qnumeric.cpp b/src/corelib/global/qnumeric.cpp
index fc2b052edf..e6ba62f530 100644
--- a/src/corelib/global/qnumeric.cpp
+++ b/src/corelib/global/qnumeric.cpp
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2016 The Qt Company Ltd.
+** Copyright (C) 2019 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtCore module of the Qt Toolkit.
@@ -46,6 +46,7 @@ QT_BEGIN_NAMESPACE
/*!
Returns \c true if the double \a {d} is equivalent to infinity.
\relates <QtGlobal>
+ \sa qInf()
*/
Q_CORE_EXPORT bool qIsInf(double d) { return qt_is_inf(d); }
@@ -64,6 +65,7 @@ Q_CORE_EXPORT bool qIsFinite(double d) { return qt_is_finite(d); }
/*!
Returns \c true if the float \a {f} is equivalent to infinity.
\relates <QtGlobal>
+ \sa qInf()
*/
Q_CORE_EXPORT bool qIsInf(float f) { return qt_is_inf(f); }
@@ -88,15 +90,36 @@ Q_CORE_EXPORT double qSNaN() { return qt_snan(); }
/*!
Returns the bit pattern of a quiet NaN as a double.
\relates <QtGlobal>
+ \sa qIsNaN()
*/
Q_CORE_EXPORT double qQNaN() { return qt_qnan(); }
/*!
Returns the bit pattern for an infinite number as a double.
\relates <QtGlobal>
+ \sa qIsInf()
*/
Q_CORE_EXPORT double qInf() { return qt_inf(); }
+/*!
+ \relates <QtGlobal>
+ Classifies a floating-point value.
+
+ The return values are defined in \c{<cmath>}: returns one of the following,
+ determined by the floating-point class of \a val:
+ \list
+ \li FP_NAN not a number
+ \li FP_INFINITE infinities (positive or negative)
+ \li FP_NORMAL finite with a full mantissa
+ \li FP_SUBNORMAL finite with a reduced mantissa
+ \endlist
+*/
+Q_CORE_EXPORT int qFpClassify(double val) { return qt_fpclassify(val); }
+
+/*!
+ \overload
+*/
+Q_CORE_EXPORT int qFpClassify(float val) { return qt_fpclassify(val); }
/*!
diff --git a/src/corelib/global/qnumeric.h b/src/corelib/global/qnumeric.h
index 535a96aaec..6a0c64712f 100644
--- a/src/corelib/global/qnumeric.h
+++ b/src/corelib/global/qnumeric.h
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2016 The Qt Company Ltd.
+** Copyright (C) 2019 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtCore module of the Qt Toolkit.
@@ -48,9 +48,11 @@ QT_BEGIN_NAMESPACE
Q_CORE_EXPORT Q_DECL_CONST_FUNCTION bool qIsInf(double d);
Q_CORE_EXPORT Q_DECL_CONST_FUNCTION bool qIsNaN(double d);
Q_CORE_EXPORT Q_DECL_CONST_FUNCTION bool qIsFinite(double d);
+Q_CORE_EXPORT Q_DECL_CONST_FUNCTION int qFpClassify(double val);
Q_CORE_EXPORT Q_DECL_CONST_FUNCTION bool qIsInf(float f);
Q_CORE_EXPORT Q_DECL_CONST_FUNCTION bool qIsNaN(float f);
Q_CORE_EXPORT Q_DECL_CONST_FUNCTION bool qIsFinite(float f);
+Q_CORE_EXPORT Q_DECL_CONST_FUNCTION int qFpClassify(float val);
Q_CORE_EXPORT Q_DECL_CONST_FUNCTION double qSNaN();
Q_CORE_EXPORT Q_DECL_CONST_FUNCTION double qQNaN();
Q_CORE_EXPORT Q_DECL_CONST_FUNCTION double qInf();
diff --git a/src/corelib/global/qnumeric_p.h b/src/corelib/global/qnumeric_p.h
index 4a225b2599..56e670c477 100644
--- a/src/corelib/global/qnumeric_p.h
+++ b/src/corelib/global/qnumeric_p.h
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2016 The Qt Company Ltd.
+** Copyright (C) 2019 The Qt Company Ltd.
** Copyright (C) 2018 Intel Corporation.
** Contact: https://www.qt.io/licensing/
**
@@ -85,9 +85,11 @@ namespace qnumeric_std_wrapper {
Q_DECL_CONST_FUNCTION static inline bool math_h_isnan(double d) { using namespace std; return isnan(d); }
Q_DECL_CONST_FUNCTION static inline bool math_h_isinf(double d) { using namespace std; return isinf(d); }
Q_DECL_CONST_FUNCTION static inline bool math_h_isfinite(double d) { using namespace std; return isfinite(d); }
+Q_DECL_CONST_FUNCTION static inline int math_h_fpclassify(double d) { using namespace std; return fpclassify(d); }
Q_DECL_CONST_FUNCTION static inline bool math_h_isnan(float f) { using namespace std; return isnan(f); }
Q_DECL_CONST_FUNCTION static inline bool math_h_isinf(float f) { using namespace std; return isinf(f); }
Q_DECL_CONST_FUNCTION static inline bool math_h_isfinite(float f) { using namespace std; return isfinite(f); }
+Q_DECL_CONST_FUNCTION static inline int math_h_fpclassify(float f) { using namespace std; return fpclassify(f); }
}
QT_END_NAMESPACE
// These macros from math.h conflict with the real functions in the std namespace.
@@ -95,6 +97,7 @@ QT_END_NAMESPACE
# undef isnan
# undef isinf
# undef isfinite
+# undef fpclassify
# endif // defined(isnan)
#endif
@@ -106,16 +109,20 @@ namespace qnumeric_std_wrapper {
Q_DECL_CONST_FUNCTION static inline bool isnan(double d) { return math_h_isnan(d); }
Q_DECL_CONST_FUNCTION static inline bool isinf(double d) { return math_h_isinf(d); }
Q_DECL_CONST_FUNCTION static inline bool isfinite(double d) { return math_h_isfinite(d); }
+Q_DECL_CONST_FUNCTION static inline int fpclassify(double d) { return math_h_fpclassify(d); }
Q_DECL_CONST_FUNCTION static inline bool isnan(float f) { return math_h_isnan(f); }
Q_DECL_CONST_FUNCTION static inline bool isinf(float f) { return math_h_isinf(f); }
Q_DECL_CONST_FUNCTION static inline bool isfinite(float f) { return math_h_isfinite(f); }
+Q_DECL_CONST_FUNCTION static inline int fpclassify(float f) { return math_h_fpclassify(f); }
#else
Q_DECL_CONST_FUNCTION static inline bool isnan(double d) { return std::isnan(d); }
Q_DECL_CONST_FUNCTION static inline bool isinf(double d) { return std::isinf(d); }
Q_DECL_CONST_FUNCTION static inline bool isfinite(double d) { return std::isfinite(d); }
+Q_DECL_CONST_FUNCTION static inline int fpclassify(double d) { return std::fpclassify(d); }
Q_DECL_CONST_FUNCTION static inline bool isnan(float f) { return std::isnan(f); }
Q_DECL_CONST_FUNCTION static inline bool isinf(float f) { return std::isinf(f); }
Q_DECL_CONST_FUNCTION static inline bool isfinite(float f) { return std::isfinite(f); }
+Q_DECL_CONST_FUNCTION static inline int fpclassify(float f) { return std::fpclassify(f); }
#endif
}
@@ -157,6 +164,11 @@ Q_DECL_CONST_FUNCTION static inline bool qt_is_finite(double d)
return qnumeric_std_wrapper::isfinite(d);
}
+Q_DECL_CONST_FUNCTION static inline int qt_fpclassify(double d)
+{
+ return qnumeric_std_wrapper::fpclassify(d);
+}
+
Q_DECL_CONST_FUNCTION static inline bool qt_is_inf(float f)
{
return qnumeric_std_wrapper::isinf(f);
@@ -172,6 +184,11 @@ Q_DECL_CONST_FUNCTION static inline bool qt_is_finite(float f)
return qnumeric_std_wrapper::isfinite(f);
}
+Q_DECL_CONST_FUNCTION static inline int qt_fpclassify(float f)
+{
+ return qnumeric_std_wrapper::fpclassify(f);
+}
+
#ifndef Q_CLANG_QDOC
namespace {
/*!
diff --git a/src/corelib/kernel/qvariant.cpp b/src/corelib/kernel/qvariant.cpp
index 18c7f7648d..deba977f77 100644
--- a/src/corelib/kernel/qvariant.cpp
+++ b/src/corelib/kernel/qvariant.cpp
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2016 The Qt Company Ltd.
+** Copyright (C) 2019 The Qt Company Ltd.
** Copyright (C) 2018 Intel Corporation.
** Copyright (C) 2015 Olivier Goffart <ogoffart@woboq.com>
** Contact: https://www.qt.io/licensing/
@@ -4002,8 +4002,8 @@ static int numericCompare(const QVariant::Private *d1, const QVariant::Private *
return 0;
// only do fuzzy comparisons for finite, non-zero numbers
- int c1 = std::fpclassify(r1);
- int c2 = std::fpclassify(r2);
+ int c1 = qFpClassify(r1);
+ int c2 = qFpClassify(r2);
if ((c1 == FP_NORMAL || c1 == FP_SUBNORMAL) && (c2 == FP_NORMAL || c2 == FP_SUBNORMAL)) {
if (qFuzzyCompare(r1, r2))
return 0;
diff --git a/src/testlib/qtestcase.cpp b/src/testlib/qtestcase.cpp
index a010ea467b..d9f8dd7805 100644
--- a/src/testlib/qtestcase.cpp
+++ b/src/testlib/qtestcase.cpp
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2016 The Qt Company Ltd.
+** Copyright (C) 2019 The Qt Company Ltd.
** Copyright (C) 2016 Intel Corporation.
** Contact: https://www.qt.io/licensing/
**
@@ -2522,12 +2522,12 @@ bool QTest::compare_helper(bool success, const char *failureMsg,
template <typename T>
static bool floatingCompare(const T &t1, const T &t2)
{
- switch (std::fpclassify(t1))
+ switch (qFpClassify(t1))
{
case FP_INFINITE:
- return (t1 < 0) == (t2 < 0) && std::fpclassify(t2) == FP_INFINITE;
+ return (t1 < 0) == (t2 < 0) && qFpClassify(t2) == FP_INFINITE;
case FP_NAN:
- return std::fpclassify(t2) == FP_NAN;
+ return qFpClassify(t2) == FP_NAN;
default:
return qFuzzyCompare(t1, t2);
}
@@ -2631,7 +2631,7 @@ static void massageExponent(char *text)
template <> Q_TESTLIB_EXPORT char *QTest::toString<TYPE>(const TYPE &t) \
{ \
char *msg = new char[128]; \
- switch (std::fpclassify(t)) { \
+ switch (qFpClassify(t)) { \
case FP_INFINITE: \
qstrncpy(msg, (t < 0 ? "-inf" : "inf"), 128); \
break; \
diff --git a/tests/auto/corelib/global/qnumeric/tst_qnumeric.cpp b/tests/auto/corelib/global/qnumeric/tst_qnumeric.cpp
index f37dcbbbba..e567e465f7 100644
--- a/tests/auto/corelib/global/qnumeric/tst_qnumeric.cpp
+++ b/tests/auto/corelib/global/qnumeric/tst_qnumeric.cpp
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2016 The Qt Company Ltd.
+** Copyright (C) 2019 The Qt Company Ltd.
** Copyright (C) 2016 Intel Corporation.
** Contact: https://www.qt.io/licensing/
**
@@ -43,6 +43,7 @@ private slots:
void fuzzyCompare_data();
void fuzzyCompare();
void qNanInf();
+ void classifyfp();
void floatDistance_data();
void floatDistance();
void floatDistance_double_data();
@@ -123,6 +124,7 @@ void tst_QNumeric::qNanInf()
QVERIFY(qIsNaN(-nan));
QVERIFY(!(nan == nan));
QVERIFY(qIsNaN(0.0 * nan));
+ QCOMPARE(qFpClassify(nan), FP_NAN);
QCOMPARE(nan, nan);
QCOMPARE(nan, -nan);
QCOMPARE(nan, qQNaN());
@@ -143,6 +145,34 @@ void tst_QNumeric::qNanInf()
QVERIFY(qIsNaN(0.0 * inf));
}
+void tst_QNumeric::classifyfp()
+{
+ QCOMPARE(qFpClassify(qQNaN()), FP_NAN);
+
+ QCOMPARE(qFpClassify(qInf()), FP_INFINITE);
+ QCOMPARE(qFpClassify(-qInf()), FP_INFINITE);
+ QCOMPARE(qFpClassify(DBL_MAX * 2.0), FP_INFINITE);
+ QCOMPARE(qFpClassify(FLT_MAX * 2.f), FP_INFINITE);
+ QCOMPARE(qFpClassify(DBL_MAX * -2.0), FP_INFINITE);
+ QCOMPARE(qFpClassify(FLT_MAX * -2.f), FP_INFINITE);
+
+ QCOMPARE(qFpClassify(1.0), FP_NORMAL);
+ QCOMPARE(qFpClassify(DBL_MAX), FP_NORMAL);
+ QCOMPARE(qFpClassify(-DBL_MAX), FP_NORMAL);
+ QCOMPARE(qFpClassify(DBL_MIN), FP_NORMAL);
+ QCOMPARE(qFpClassify(-DBL_MIN), FP_NORMAL);
+ QCOMPARE(qFpClassify(DBL_MIN / 2.0), FP_SUBNORMAL);
+ QCOMPARE(qFpClassify(DBL_MIN / -2.0), FP_SUBNORMAL);
+
+ QCOMPARE(qFpClassify(1.f), FP_NORMAL);
+ QCOMPARE(qFpClassify(FLT_MAX), FP_NORMAL);
+ QCOMPARE(qFpClassify(-FLT_MAX), FP_NORMAL);
+ QCOMPARE(qFpClassify(FLT_MIN), FP_NORMAL);
+ QCOMPARE(qFpClassify(-FLT_MIN), FP_NORMAL);
+ QCOMPARE(qFpClassify(FLT_MIN / 2.f), FP_SUBNORMAL);
+ QCOMPARE(qFpClassify(FLT_MIN / -2.f), FP_SUBNORMAL);
+}
+
void tst_QNumeric::floatDistance_data()
{
QTest::addColumn<float>("val1");