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>
This commit is contained in:
parent
368eb2ecec
commit
84aea6c091
@ -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); }
|
||||
|
||||
|
||||
/*!
|
||||
|
@ -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();
|
||||
|
@ -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 {
|
||||
/*!
|
||||
|
@ -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;
|
||||
|
@ -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; \
|
||||
|
@ -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");
|
||||
|
Loading…
x
Reference in New Issue
Block a user