New qfloat16 class

This constitutes a fairly complete submission of an entirely new
floating point type which conforms to IEEE 754 as a 16-bit storage
class.  Conversion between qfloat16 and float is currently performed
through a sequence of lookup tables.  Global-level functions
qRound(), qRound64(), qFuzzyCompare(), qFuzzyIsNull(), and
qIsNull() each with a qfloat16 parameter have been included
for completeness.

[ChangeLog][QtCore] Added new qfloat16 class.

Change-Id: Ia52eb27846965c14f8140c00faf5ba33c9443976
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
bb10
Glen Mabey 2013-06-22 19:43:46 -05:00
parent e5d303cb9f
commit 3ab7016632
13 changed files with 932 additions and 4 deletions

2
.gitignore vendored
View File

@ -89,6 +89,7 @@ bin/makeqpf*
bin/pixeltool*
bin/qmake*
bin/qdoc*
bin/qfloat16-tables*
bin/qt3to4*
bin/qttracereplay*
bin/rcc*
@ -137,6 +138,7 @@ src/corelib/global/qconfig.h
src/corelib/global/qconfig.h.qmake
src/corelib/global/qconfig_p.h
src/corelib/global/qfeatures.h
src/corelib/global/qfloat16tables.cpp
src/platformsupport/*_interface.*
src/platformsupport/*_adaptor.*
ui_*.h

View File

@ -11,6 +11,8 @@ HEADERS += \
global/qendian.h \
global/qnumeric_p.h \
global/qnumeric.h \
global/qfloat16_p.h \
global/qfloat16.h \
global/qglobalstatic.h \
global/qlibraryinfo.h \
global/qlogging.h \
@ -29,6 +31,7 @@ SOURCES += \
global/qlibraryinfo.cpp \
global/qmalloc.cpp \
global/qnumeric.cpp \
global/qfloat16.cpp \
global/qoperatingsystemversion.cpp \
global/qlogging.cpp \
global/qhooks.cpp
@ -76,3 +79,14 @@ gcc:ltcg {
} else {
SOURCES += $$VERSIONTAGGING_SOURCES
}
QMAKE_QFLOAT16_TABLES_GENERATE = global/qfloat16.h
qtPrepareTool(QMAKE_QFLOAT16_TABLES, qfloat16-tables)
qfloat16_tables.commands = $$QMAKE_QFLOAT16_TABLES ${QMAKE_FILE_OUT}
qfloat16_tables.output = global/qfloat16tables.cpp
qfloat16_tables.depends = $$QMAKE_QFLOAT16_TABLES
qfloat16_tables.input = QMAKE_QFLOAT16_TABLES_GENERATE
qfloat16_tables.variable_out = SOURCES
QMAKE_EXTRA_COMPILERS += qfloat16_tables

View File

@ -0,0 +1,117 @@
/****************************************************************************
**
** Copyright (C) 2016 by Southwest Research Institute (R)
** Contact: http://www.qt-project.org/legal
**
** This file is part of the QtCore module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 3 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL3 included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 3 requirements
** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 2.0 or (at your option) the GNU General
** Public license version 3 or any later version approved by the KDE Free
** Qt Foundation. The licenses are as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-2.0.html and
** https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include "qfloat16_p.h"
QT_BEGIN_NAMESPACE
/*! \headerfile <QFloat16>
This header file provides support for half-precision (16-bit) floating
point data with the class \c qfloat16. It is fully compliant with IEEE
754 as a storage type. This implies that any arithmetic operation on a
\c qfloat16 instance results in the value first being converted to a
\c float. This conversion to and from \c float is performed by hardware
when possible, but on processors that do not natively support half-precision,
the conversion is performed through a sequence of lookup table operations.
\c qfloat16 should be treated as if it were a POD (plain old data) type.
Consequently, none of the supported operations need any elaboration beyond
stating that it supports all arithmetic operators incident to floating point
types.
\since 5.9
*/
Q_STATIC_ASSERT_X(sizeof(float) == sizeof(quint32),
"qfloat16 assumes that floats are 32 bits wide");
Q_STATIC_ASSERT_X(std::numeric_limits<float>::is_iec559,
"Only works with IEEE 754 floating point");
/*!
Returns true if the \c qfloat16 \a {f} is equivalent to infinity.
\relates <QFloat16>
\sa qIsInf
*/
Q_REQUIRED_RESULT bool qIsInf(qfloat16 f) Q_DECL_NOTHROW { return qt_is_inf(f); }
/*!
Returns true if the \c qfloat16 \a {f} is not a number (NaN).
\relates <QFloat16>
\sa qIsNaN
*/
Q_REQUIRED_RESULT bool qIsNaN(qfloat16 f) Q_DECL_NOTHROW { return qt_is_nan(f); }
/*!
Returns true if the \c qfloat16 \a {f} is a finite number.
\relates <QFloat16>
\sa qIsFinite
*/
Q_REQUIRED_RESULT bool qIsFinite(qfloat16 f) Q_DECL_NOTHROW { return qt_is_finite(f); }
/*! \fn int qRound(qfloat16 value)
\relates <QFloat16>
Rounds \a value to the nearest integer.
\sa qRound
*/
/*! \fn qint64 qRound64(qfloat16 value)
\relates <QFloat16>
Rounds \a value to the nearest 64-bit integer.
\sa qRound64
*/
/*! \fn bool qFuzzyCompare(qfloat16 p1, qfloat16 p2)
\relates <QFloat16>
Compares the floating point value \a p1 and \a p2 and
returns \c true if they are considered equal, otherwise \c false.
The two numbers are compared in a relative way, where the
exactness is stronger the smaller the numbers are.
*/
QT_END_NAMESPACE

View File

@ -0,0 +1,225 @@
/****************************************************************************
**
** Copyright (C) 2016 by Southwest Research Institute (R)
** Contact: http://www.qt-project.org/legal
**
** This file is part of the QtCore module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 3 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL3 included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 3 requirements
** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 2.0 or (at your option) the GNU General
** Public license version 3 or any later version approved by the KDE Free
** Qt Foundation. The licenses are as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-2.0.html and
** https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#ifndef QFLOAT16_H
#define QFLOAT16_H
#include <QtCore/qglobal.h>
#include <QtCore/qmetatype.h>
#include <string.h>
QT_BEGIN_NAMESPACE
#if 0
#pragma qt_class(QFloat16)
#endif
class qfloat16
{
public:
#ifndef Q_QDOC
Q_DECL_CONSTEXPR inline qfloat16() Q_DECL_NOTHROW : b16(0) { }
inline qfloat16(float f) Q_DECL_NOTHROW;
inline operator float() const Q_DECL_NOTHROW;
inline operator double() const Q_DECL_NOTHROW;
inline operator long double() const Q_DECL_NOTHROW;
#endif
private:
quint16 b16;
Q_CORE_EXPORT static const quint32 mantissatable[];
Q_CORE_EXPORT static const quint32 exponenttable[];
Q_CORE_EXPORT static const quint32 offsettable[];
Q_CORE_EXPORT static const quint32 basetable[];
Q_CORE_EXPORT static const quint32 shifttable[];
friend bool qIsNull(qfloat16 f) Q_DECL_NOTHROW;
friend qfloat16 operator-(qfloat16 a) Q_DECL_NOTHROW;
};
Q_DECLARE_TYPEINFO(qfloat16, Q_PRIMITIVE_TYPE);
Q_CORE_EXPORT Q_REQUIRED_RESULT bool qIsInf(qfloat16 f) Q_DECL_NOTHROW; // complements qnumeric.h
Q_CORE_EXPORT Q_REQUIRED_RESULT bool qIsNaN(qfloat16 f) Q_DECL_NOTHROW; // complements qnumeric.h
Q_CORE_EXPORT Q_REQUIRED_RESULT bool qIsFinite(qfloat16 f) Q_DECL_NOTHROW; // complements qnumeric.h
// The remainder of these utility functions complement qglobal.h
inline Q_REQUIRED_RESULT int qRound(qfloat16 d) Q_DECL_NOTHROW
{ return qRound(static_cast<float>(d)); }
inline Q_REQUIRED_RESULT qint64 qRound64(qfloat16 d) Q_DECL_NOTHROW
{ return qRound64(static_cast<float>(d)); }
inline Q_REQUIRED_RESULT bool qFuzzyCompare(qfloat16 p1, qfloat16 p2) Q_DECL_NOTHROW
{
float f1 = static_cast<float>(p1);
float f2 = static_cast<float>(p2);
// The significand precision for IEEE754 half precision is
// 11 bits (10 explicitly stored), or approximately 3 decimal
// digits. In selecting the fuzzy comparison factor of 102.5f
// (that is, (2^10+1)/10) below, we effectively select a
// window of about 1 (least significant) decimal digit about
// which the two operands can vary and still return true.
return (qAbs(f1 - f2) * 102.5f <= qMin(qAbs(f1), qAbs(f2)));
}
inline Q_REQUIRED_RESULT bool qIsNull(qfloat16 f) Q_DECL_NOTHROW
{
return (f.b16 & static_cast<quint16>(0x7fff)) == 0;
}
inline int qIntCast(qfloat16 f) Q_DECL_NOTHROW
{ return int(static_cast<float>(f)); }
inline qfloat16::qfloat16(float f) Q_DECL_NOTHROW
{
quint32 u;
memcpy(&u, &f, sizeof(quint32));
b16 = basetable[(u >> 23) & 0x1ff]
+ ((u & 0x007fffff) >> shifttable[(u >> 23) & 0x1ff]);
}
inline qfloat16::operator float() const Q_DECL_NOTHROW
{
quint32 u = mantissatable[offsettable[b16 >> 10] + (b16 & 0x3ff)]
+ exponenttable[b16 >> 10];
float f;
memcpy(&f, &u, sizeof(quint32));
return f;
}
inline qfloat16::operator double() const Q_DECL_NOTHROW
{
return static_cast<double>(float(*this));
}
inline qfloat16::operator long double() const Q_DECL_NOTHROW
{
return static_cast<long double>(float(*this));
}
inline qfloat16 operator-(qfloat16 a) Q_DECL_NOTHROW
{
qfloat16 f;
f.b16 = a.b16 ^ quint16(0x8000);
return f;
}
inline qfloat16 operator+(qfloat16 a, qfloat16 b) Q_DECL_NOTHROW { return qfloat16(static_cast<float>(a) + static_cast<float>(b)); }
inline qfloat16 operator-(qfloat16 a, qfloat16 b) Q_DECL_NOTHROW { return qfloat16(static_cast<float>(a) - static_cast<float>(b)); }
inline qfloat16 operator*(qfloat16 a, qfloat16 b) Q_DECL_NOTHROW { return qfloat16(static_cast<float>(a) * static_cast<float>(b)); }
inline qfloat16 operator/(qfloat16 a, qfloat16 b) Q_DECL_NOTHROW { return qfloat16(static_cast<float>(a) / static_cast<float>(b)); }
#define QF16_MAKE_ARITH_OP_FP(FP, OP) \
inline FP operator OP(qfloat16 lhs, FP rhs) Q_DECL_NOTHROW { return static_cast<FP>(lhs) OP rhs; } \
inline FP operator OP(FP lhs, qfloat16 rhs) Q_DECL_NOTHROW { return lhs OP static_cast<FP>(rhs); }
#define QF16_MAKE_ARITH_OP_EQ_FP(FP, OP_EQ, OP) \
inline qfloat16& operator OP_EQ(qfloat16& lhs, FP rhs) Q_DECL_NOTHROW { lhs = qfloat16(static_cast<FP>(lhs) OP rhs); return lhs; }
#define QF16_MAKE_ARITH_OP(FP) \
QF16_MAKE_ARITH_OP_FP(FP, +) \
QF16_MAKE_ARITH_OP_FP(FP, -) \
QF16_MAKE_ARITH_OP_FP(FP, *) \
QF16_MAKE_ARITH_OP_FP(FP, /) \
QF16_MAKE_ARITH_OP_EQ_FP(FP, +=, +) \
QF16_MAKE_ARITH_OP_EQ_FP(FP, -=, -) \
QF16_MAKE_ARITH_OP_EQ_FP(FP, *=, *) \
QF16_MAKE_ARITH_OP_EQ_FP(FP, /=, /)
QF16_MAKE_ARITH_OP(long double)
QF16_MAKE_ARITH_OP(double)
QF16_MAKE_ARITH_OP(float)
#undef QF16_MAKE_ARITH_OP
#undef QF16_MAKE_ARITH_OP_FP
#define QF16_MAKE_ARITH_OP_INT(OP) \
inline double operator OP(qfloat16 lhs, int rhs) Q_DECL_NOTHROW { return static_cast<double>(lhs) OP rhs; } \
inline double operator OP(int lhs, qfloat16 rhs) Q_DECL_NOTHROW { return lhs OP static_cast<double>(rhs); }
QF16_MAKE_ARITH_OP_INT(+)
QF16_MAKE_ARITH_OP_INT(-)
QF16_MAKE_ARITH_OP_INT(*)
QF16_MAKE_ARITH_OP_INT(/)
#undef QF16_MAKE_ARITH_OP_INT
inline bool operator>(qfloat16 a, qfloat16 b) Q_DECL_NOTHROW { return static_cast<float>(a) > static_cast<float>(b); }
inline bool operator<(qfloat16 a, qfloat16 b) Q_DECL_NOTHROW { return static_cast<float>(a) < static_cast<float>(b); }
inline bool operator>=(qfloat16 a, qfloat16 b) Q_DECL_NOTHROW { return static_cast<float>(a) >= static_cast<float>(b); }
inline bool operator<=(qfloat16 a, qfloat16 b) Q_DECL_NOTHROW { return static_cast<float>(a) <= static_cast<float>(b); }
inline bool operator==(qfloat16 a, qfloat16 b) Q_DECL_NOTHROW { return static_cast<float>(a) == static_cast<float>(b); }
inline bool operator!=(qfloat16 a, qfloat16 b) Q_DECL_NOTHROW { return static_cast<float>(a) != static_cast<float>(b); }
#define QF16_MAKE_BOOL_OP_FP(FP, OP) \
inline bool operator OP(qfloat16 lhs, FP rhs) Q_DECL_NOTHROW { return static_cast<FP>(lhs) OP rhs; } \
inline bool operator OP(FP lhs, qfloat16 rhs) Q_DECL_NOTHROW { return lhs OP static_cast<FP>(rhs); }
#define QF16_MAKE_BOOL_OP(FP) \
QF16_MAKE_BOOL_OP_FP(FP, <) \
QF16_MAKE_BOOL_OP_FP(FP, >) \
QF16_MAKE_BOOL_OP_FP(FP, >=) \
QF16_MAKE_BOOL_OP_FP(FP, <=) \
QF16_MAKE_BOOL_OP_FP(FP, ==) \
QF16_MAKE_BOOL_OP_FP(FP, !=)
QF16_MAKE_BOOL_OP(long double)
QF16_MAKE_BOOL_OP(double)
QF16_MAKE_BOOL_OP(float)
#undef QF16_MAKE_BOOL_OP
#undef QF16_MAKE_BOOL_OP_FP
#define QF16_MAKE_BOOL_OP_INT(OP) \
inline bool operator OP(qfloat16 a, int b) Q_DECL_NOTHROW { return static_cast<float>(a) OP b; } \
inline bool operator OP(int a, qfloat16 b) Q_DECL_NOTHROW { return a OP static_cast<float>(b); }
QF16_MAKE_BOOL_OP_INT(>)
QF16_MAKE_BOOL_OP_INT(<)
QF16_MAKE_BOOL_OP_INT(>=)
QF16_MAKE_BOOL_OP_INT(<=)
QF16_MAKE_BOOL_OP_INT(==)
QF16_MAKE_BOOL_OP_INT(!=)
#undef QF16_MAKE_BOOL_OP_INT
/*!
\internal
*/
inline Q_REQUIRED_RESULT bool qFuzzyIsNull(qfloat16 f) Q_DECL_NOTHROW
{
return qAbs(static_cast<float>(f)) <= 0.001f;
}
QT_END_NAMESPACE
Q_DECLARE_METATYPE(qfloat16)
#endif // QFLOAT16_H

View File

@ -0,0 +1,95 @@
/****************************************************************************
**
** Copyright (C) 2016 by Southwest Research Institute (R)
** Contact: http://www.qt-project.org/legal
**
** This file is part of the QtCore module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 3 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL3 included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 3 requirements
** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 2.0 or (at your option) the GNU General
** Public license version 3 or any later version approved by the KDE Free
** Qt Foundation. The licenses are as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-2.0.html and
** https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#ifndef QFLOAT16_P_H
#define QFLOAT16_P_H
//
// W A R N I N G
// -------------
//
// This file is not part of the Qt API. It exists purely as an
// implementation detail. This header file may change from version to
// version without notice, or even be removed.
//
// We mean it.
//
#include <QtCore/qfloat16.h>
#include <QtCore/qsysinfo.h>
QT_BEGIN_NAMESPACE
static inline bool qt_is_inf(qfloat16 d) Q_DECL_NOTHROW
{
bool is_inf;
uchar *ch = (uchar *)&d;
if (QSysInfo::ByteOrder == QSysInfo::BigEndian)
is_inf = (ch[0] & 0x7c) == 0x7c;
else
is_inf = (ch[1] & 0x7c) == 0x7c;
return is_inf;
}
static inline bool qt_is_nan(qfloat16 d) Q_DECL_NOTHROW
{
bool is_nan;
uchar *ch = (uchar *)&d;
if (QSysInfo::ByteOrder == QSysInfo::BigEndian)
is_nan = (ch[0] & 0x7c) == 0x7c && (ch[0] & 0x02) != 0;
else
is_nan = (ch[1] & 0x7c) == 0x7c && (ch[1] & 0x02) != 0;
return is_nan;
}
static inline bool qt_is_finite(qfloat16 d) Q_DECL_NOTHROW
{
bool is_finite;
uchar *ch = (uchar *)&d;
if (QSysInfo::ByteOrder == QSysInfo::BigEndian)
is_finite = (ch[0] & 0x7c) != 0x7c;
else
is_finite = (ch[1] & 0x7c) != 0x7c;
return is_finite;
}
QT_END_NAMESPACE
#endif // QFLOAT16_P_H

View File

@ -448,6 +448,9 @@ QDataStream::FloatingPointPrecision QDataStream::floatingPointPrecision() const
The default is DoublePrecision.
Note that this property does not affect the serialization or deserialization of \c qfloat16
instances.
\warning This property must be set to the same value on the object that writes and the object
that reads the data stream.
@ -971,6 +974,16 @@ QDataStream &QDataStream::operator>>(double &f)
}
/*!
\fn QDataStream &QDataStream::operator>>(qfloat16 &f)
\overload
\since 5.9
Reads a floating point number from the stream into \a f,
using the standard IEEE 754 format. Returns a reference to the
stream.
*/
/*!
\overload
@ -1259,6 +1272,15 @@ QDataStream &QDataStream::operator<<(double f)
}
/*!
\fn QDataStream &QDataStream::operator<<(qfloat16 f)
\overload
\since 5.9
Writes a floating point number, \a f, to the stream using
the standard IEEE 754 format. Returns a reference to the stream.
*/
/*!
\overload
@ -1282,7 +1304,6 @@ QDataStream &QDataStream::operator<<(const char *s)
return *this;
}
/*!
Writes the length specifier \a len and the buffer \a s to the
stream and returns a reference to the stream.

View File

@ -43,6 +43,7 @@
#include <QtCore/qscopedpointer.h>
#include <QtCore/qiodevice.h>
#include <QtCore/qpair.h>
#include <QtCore/qfloat16.h>
#ifdef Status
#error qdatastream.h must be included before any header file that defines Status
@ -154,6 +155,7 @@ public:
QDataStream &operator>>(quint64 &i);
QDataStream &operator>>(bool &i);
QDataStream &operator>>(qfloat16 &f);
QDataStream &operator>>(float &f);
QDataStream &operator>>(double &f);
QDataStream &operator>>(char *&str);
@ -167,6 +169,7 @@ public:
QDataStream &operator<<(qint64 i);
QDataStream &operator<<(quint64 i);
QDataStream &operator<<(bool i);
QDataStream &operator<<(qfloat16 f);
QDataStream &operator<<(float f);
QDataStream &operator<<(double f);
QDataStream &operator<<(const char *str);
@ -345,6 +348,9 @@ inline QDataStream &QDataStream::operator>>(quint32 &i)
inline QDataStream &QDataStream::operator>>(quint64 &i)
{ return *this >> reinterpret_cast<qint64&>(i); }
inline QDataStream &QDataStream::operator>>(qfloat16 &f)
{ return *this >> reinterpret_cast<qint16&>(f); }
inline QDataStream &QDataStream::operator<<(quint8 i)
{ return *this << qint8(i); }
@ -357,6 +363,9 @@ inline QDataStream &QDataStream::operator<<(quint32 i)
inline QDataStream &QDataStream::operator<<(quint64 i)
{ return *this << qint64(i); }
inline QDataStream &QDataStream::operator<<(qfloat16 f)
{ return *this << reinterpret_cast<qint16&>(f); }
template <typename T>
inline QDataStream &operator>>(QDataStream &s, QList<T> &l)
{

View File

@ -21,6 +21,10 @@ src_tools_rcc.subdir = tools/rcc
src_tools_rcc.target = sub-rcc
src_tools_rcc.depends = src_tools_bootstrap
src_tools_qfloat16_tables.subdir = tools/qfloat16-tables
src_tools_qfloat16_tables.target = sub-qfloat16-tables
src_tools_qfloat16_tables.depends = src_tools_bootstrap
src_tools_qlalr.subdir = tools/qlalr
src_tools_qlalr.target = sub-qlalr
force_bootstrap: src_tools_qlalr.depends = src_tools_bootstrap
@ -51,7 +55,7 @@ src_winmain.depends = sub-corelib # just for the module .pri file
src_corelib.subdir = $$PWD/corelib
src_corelib.target = sub-corelib
src_corelib.depends = src_tools_moc src_tools_rcc
src_corelib.depends = src_tools_moc src_tools_rcc src_tools_qfloat16_tables
src_xml.subdir = $$PWD/xml
src_xml.target = sub-xml
@ -135,13 +139,13 @@ src_android.subdir = $$PWD/android
src_3rdparty_freetype.depends += src_corelib
}
}
SUBDIRS += src_tools_bootstrap src_tools_moc src_tools_rcc
SUBDIRS += src_tools_bootstrap src_tools_moc src_tools_rcc src_tools_qfloat16_tables
qtConfig(regularexpression):pcre2 {
SUBDIRS += src_3rdparty_pcre2
src_corelib.depends += src_3rdparty_pcre2
}
SUBDIRS += src_corelib src_tools_qlalr
TOOLS = src_tools_moc src_tools_rcc src_tools_qlalr
TOOLS = src_tools_moc src_tools_rcc src_tools_qlalr src_tools_qfloat16_tables
win32:SUBDIRS += src_winmain
qtConfig(network) {
SUBDIRS += src_network

View File

@ -0,0 +1,161 @@
/****************************************************************************
**
** Copyright (C) 2016 by Southwest Research Institute (R)
** Contact: http://www.qt-project.org/legal
**
** This file is part of the QtCore module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 3 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL3 included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 3 requirements
** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 2.0 or (at your option) the GNU General
** Public license version 3 or any later version approved by the KDE Free
** Qt Foundation. The licenses are as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-2.0.html and
** https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include <qfile.h>
#include <qdebug.h>
quint32 convertmantissa(qint32 i)
{
quint32 m = i << 13; // Zero pad mantissa bits
quint32 e = 0; // Zero exponent
while (!(m & 0x00800000)) { // While not normalized
e -= 0x00800000; // Decrement exponent (1<<23)
m <<= 1; // Shift mantissa
}
m &= ~0x00800000; // Clear leading 1 bit
e += 0x38800000; // Adjust bias ((127-14)<<23)
return m | e; // Return combined number
}
// we first build these tables up and then print them out as a separate step in order
// to more closely map the implementation given in the paper.
quint32 basetable[512];
quint32 shifttable[512];
#define PRINTHEX(a) "0x" + QByteArray::number(a,16).toUpper() + "U,\n"
qint32 main(qint32 argc, char **argv)
{
if (argc < 2) {
qWarning() << "Must provide output filename as argument.";
return -1;
}
QFile fid(argv[1]);
if (!fid.open(QIODevice::WriteOnly | QIODevice::Text)) {
qWarning() << "Abort: Failed to open/create file" << fid.fileName();
return -1;
}
quint32 i;
fid.write("/* This file was generated by gen_qfloat16_tables.cpp */\n\n");
fid.write("#include <QtCore/qfloat16.h>\n\n");
fid.write("QT_BEGIN_NAMESPACE\n\n");
fid.write("const quint32 qfloat16::mantissatable[2048] = {\n");
fid.write("0,\n");
for (i = 1; i < 1024; i++)
fid.write(PRINTHEX(convertmantissa(i)));
for (i = 1024; i < 2048; i++)
fid.write(PRINTHEX(0x38000000U + ((i - 1024) << 13)));
fid.write("};\n\n");
fid.write("const quint32 qfloat16::exponenttable[64] = {\n");
fid.write("0,\n");
for (i = 1; i < 31; i++)
fid.write(PRINTHEX(i << 23));
fid.write("0x47800000U,\n"); // 31
fid.write("0x80000000U,\n"); // 32
for (i = 33; i < 63; i++)
fid.write(PRINTHEX(0x80000000U + ((i - 32) << 23)));
fid.write("0xC7800000U,\n"); // 63
fid.write("};\n\n");
fid.write("const quint32 qfloat16::offsettable[64] = {\n");
fid.write("0,\n");
for (i = 1; i < 32; i++)
fid.write("1024U,\n");
fid.write("0,\n");
for (i = 33; i < 64; i++)
fid.write("1024U,\n");
fid.write("};\n\n");
qint32 e;
for (i = 0; i < 256; ++i) {
e = i - 127;
if (e < -24) { // Very small numbers map to zero
basetable[i | 0x000] = 0x0000;
basetable[i | 0x100] = 0x8000;
shifttable[i | 0x000] = 24;
shifttable[i | 0x100] = 24;
} else if (e < -14) { // Small numbers map to denorms
basetable[i | 0x000] = (0x0400 >> (-e - 14));
basetable[i | 0x100] = (0x0400 >> (-e - 14)) | 0x8000;
shifttable[i | 0x000] = -e - 1;
shifttable[i | 0x100] = -e - 1;
} else if (e <= 15) { // Normal numbers just lose precision
basetable[i | 0x000] = ((e + 15) << 10);
basetable[i | 0x100] = ((e + 15) << 10) | 0x8000;
shifttable[i | 0x000] = 13;
shifttable[i | 0x100] = 13;
} else if (e < 128) { // Large numbers map to Infinity
basetable[i | 0x000] = 0x7C00;
basetable[i | 0x100] = 0xFC00;
shifttable[i | 0x000] = 24;
shifttable[i | 0x100] = 24;
} else { // Infinity and NaN's stay Infinity and NaN's
basetable[i | 0x000] = 0x7C00;
basetable[i | 0x100] = 0xFC00;
shifttable[i | 0x000] = 13;
shifttable[i | 0x100] = 13;
}
}
fid.write("const quint32 qfloat16::basetable[512] = {\n");
for (i = 0; i < 512; i++)
fid.write(PRINTHEX(basetable[i]));
fid.write("};\n\n");
fid.write("const quint32 qfloat16::shifttable[512] = {\n");
for (i = 0; i < 512; i++)
fid.write(PRINTHEX(shifttable[i]));
fid.write("};\n\n");
fid.write("QT_END_NAMESPACE\n");
fid.close();
return 0;
}

View File

@ -0,0 +1,9 @@
option(host_build)
CONFIG += force_bootstrap
SOURCES += gen_qfloat16_tables.cpp
load(qt_tool)
lib.CONFIG = dummy_install
INSTALLS = lib

View File

@ -5,6 +5,7 @@ SUBDIRS=\
qgetputenv \
qglobal \
qnumeric \
qfloat16 \
qrand \
qlogging \
qtendian \

View File

@ -0,0 +1,4 @@
CONFIG += testcase
TARGET = tst_qfloat16
QT = core testlib
SOURCES = tst_qfloat16.cpp

View File

@ -0,0 +1,266 @@
/****************************************************************************
**
** Copyright (C) 2016 by Southwest Research Institute (R)
** Contact: http://www.qt-project.org/legal
**
** This file is part of the QtCore module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 3 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL3 included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 3 requirements
** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 2.0 or (at your option) the GNU General
** Public license version 3 or any later version approved by the KDE Free
** Qt Foundation. The licenses are as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-2.0.html and
** https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include <QtTest/QtTest>
#include <QFloat16>
#include <math.h>
class tst_qfloat16: public QObject
{
Q_OBJECT
private slots:
void fuzzyCompare_data();
void fuzzyCompare();
void ltgt_data();
void ltgt();
void qNan();
void float_cast();
void float_cast_data();
void promotionTests();
};
void tst_qfloat16::fuzzyCompare_data()
{
QTest::addColumn<qfloat16>("val1");
QTest::addColumn<qfloat16>("val2");
QTest::addColumn<bool>("fuzEqual");
QTest::addColumn<bool>("isEqual");
QTest::newRow("zero") << qfloat16(0.0f) << qfloat16(0.0f) << true << true;
QTest::newRow("ten") << qfloat16(1e1f) << qfloat16(1e1f) << true << true;
QTest::newRow("large") << qfloat16(1e4f) << qfloat16(1e4f) << true << true;
QTest::newRow("small") << qfloat16(1e-5f) << qfloat16(1e-5f) << true << true;
QTest::newRow("eps") << qfloat16(10.01f) << qfloat16(10.02f) << true << false;
QTest::newRow("eps2") << qfloat16(1024.f) << qfloat16(1033.f) << true << false;
QTest::newRow("mis1") << qfloat16(0.0f) << qfloat16(1.0f) << false << false;
QTest::newRow("mis2") << qfloat16(0.0f) << qfloat16(1e7f) << false << false;
QTest::newRow("mis3") << qfloat16(0.0f) << qfloat16(1e-4f) << false << false;
QTest::newRow("mis4") << qfloat16(1e8f) << qfloat16(1e-8f) << false << false;
QTest::newRow("mis5") << qfloat16(1e-4f) << qfloat16(1e-5) << false << false;
QTest::newRow("mis6") << qfloat16(1024.f) << qfloat16(1034.f) << false << false;
}
void tst_qfloat16::fuzzyCompare()
{
QFETCH(qfloat16, val1);
QFETCH(qfloat16, val2);
QFETCH(bool, fuzEqual);
QFETCH(bool, isEqual);
if (!isEqual && (val1==val2))
qWarning() << "Identical arguments provided unintentionally!";
if (fuzEqual) {
QVERIFY(::qFuzzyCompare(val1, val2));
QVERIFY(::qFuzzyCompare(val2, val1));
QVERIFY(::qFuzzyCompare(-val1, -val2));
QVERIFY(::qFuzzyCompare(-val2, -val1));
} else {
QVERIFY(!::qFuzzyCompare(val1, val2));
QVERIFY(!::qFuzzyCompare(val2, val1));
QVERIFY(!::qFuzzyCompare(-val1, -val2));
QVERIFY(!::qFuzzyCompare(-val2, -val1));
}
}
void tst_qfloat16::ltgt_data()
{
QTest::addColumn<float>("val1");
QTest::addColumn<float>("val2");
QTest::newRow("zero") << 0.0f << 0.0f;
QTest::newRow("ten") << 10.0f << 10.0f;
QTest::newRow("large") << 100000.0f << 100000.0f;
QTest::newRow("small") << 0.0000001f << 0.0000001f;
QTest::newRow("eps") << 10.000000000000001f << 10.00000000000002f;
QTest::newRow("eps2") << 10.000000000000001f << 10.000000000000009f;
QTest::newRow("mis1") << 0.0f << 1.0f;
QTest::newRow("mis2") << 0.0f << 10000000.0f;
QTest::newRow("mis3") << 0.0f << 0.0001f;
QTest::newRow("mis4") << 100000000.0f << 0.000000001f;
QTest::newRow("mis5") << 0.0001f << 0.00001f;
QTest::newRow("45,23") << 45.f << 23.f;
QTest::newRow("1000,76") << 1000.f << 76.f;
}
void tst_qfloat16::ltgt()
{
QFETCH(float, val1);
QFETCH(float, val2);
QCOMPARE(qfloat16(val1) == qfloat16(val2), val1 == val2);
QCOMPARE(qfloat16(val1) < qfloat16(val2), val1 < val2);
QCOMPARE(qfloat16(val1) <= qfloat16(val2), val1 <= val2);
QCOMPARE(qfloat16(val1) > qfloat16(val2), val1 > val2);
QCOMPARE(qfloat16(val1) >= qfloat16(val2), val1 >= val2);
QCOMPARE(qfloat16(val1) == qfloat16(-val2), val1 == -val2);
QCOMPARE(qfloat16(val1) < qfloat16(-val2), val1 < -val2);
QCOMPARE(qfloat16(val1) <= qfloat16(-val2), val1 <= -val2);
QCOMPARE(qfloat16(val1) > qfloat16(-val2), val1 > -val2);
QCOMPARE(qfloat16(val1) >= qfloat16(-val2), val1 >= -val2);
QCOMPARE(qfloat16(-val1) == qfloat16(val2), -val1 == val2);
QCOMPARE(qfloat16(-val1) < qfloat16(val2), -val1 < val2);
QCOMPARE(qfloat16(-val1) <= qfloat16(val2), -val1 <= val2);
QCOMPARE(qfloat16(-val1) > qfloat16(val2), -val1 > val2);
QCOMPARE(qfloat16(-val1) >= qfloat16(val2), -val1 >= val2);
QCOMPARE(qfloat16(-val1) == qfloat16(-val2), -val1 == -val2);
QCOMPARE(qfloat16(-val1) < qfloat16(-val2), -val1 < -val2);
QCOMPARE(qfloat16(-val1) <= qfloat16(-val2), -val1 <= -val2);
QCOMPARE(qfloat16(-val1) > qfloat16(-val2), -val1 > -val2);
QCOMPARE(qfloat16(-val1) >= qfloat16(-val2), -val1 >= -val2);
}
#if defined __FAST_MATH__ && (__GNUC__ * 100 + __GNUC_MINOR__ >= 404)
// turn -ffast-math off
# pragma GCC optimize "no-fast-math"
#endif
void tst_qfloat16::qNan()
{
#if defined __FAST_MATH__ && (__GNUC__ * 100 + __GNUC_MINOR__ < 404)
QSKIP("Non-conformant fast math mode is enabled, cannot run test");
#endif
qfloat16 nan = qQNaN();
QVERIFY(!(0. > nan));
QVERIFY(!(0. < nan));
QVERIFY(qIsNaN(nan));
QVERIFY(qIsNaN(nan + 1.f));
QVERIFY(qIsNaN(-nan));
qfloat16 inf = qInf();
QVERIFY(inf > qfloat16(0));
QVERIFY(-inf < qfloat16(0));
QVERIFY(qIsInf(inf));
QVERIFY(qIsInf(-inf));
QVERIFY(qIsInf(2.f*inf));
QVERIFY(qIsInf(inf*2.f));
QCOMPARE(qfloat16(1.f/inf), qfloat16(0.f));
#ifdef Q_CC_INTEL
QEXPECT_FAIL("", "ICC optimizes zero * anything to zero", Continue);
#endif
QVERIFY(qIsNaN(nan*0.f));
#ifdef Q_CC_INTEL
QEXPECT_FAIL("", "ICC optimizes zero * anything to zero", Continue);
#endif
QVERIFY(qIsNaN(inf*0.f));
QVERIFY(qFuzzyCompare(qfloat16(1.f/inf), qfloat16(0.0)));
}
void tst_qfloat16::float_cast_data()
{
QTest::addColumn<float>("val");
QTest::newRow("zero") << 0.f;
QTest::newRow("one") << 1e0f;
QTest::newRow("ten") << 1e1f;
QTest::newRow("hund") << 1e2f;
QTest::newRow("thou") << 1e3f;
QTest::newRow("tthou") << 1e4f;
//QTest::newRow("hthou") << 1e5f;
//QTest::newRow("mil") << 1e6f;
//QTest::newRow("tmil") << 1e7f;
//QTest::newRow("hmil") << 1e8f;
}
void tst_qfloat16::float_cast()
{
QFETCH(float, val);
QVERIFY(qFuzzyCompare(float(qfloat16(val)),val));
QVERIFY(qFuzzyCompare(float(qfloat16(-val)),-val));
}
void tst_qfloat16::promotionTests()
{
QCOMPARE(sizeof(qfloat16),sizeof(qfloat16(1.f)+qfloat16(1.f)));
QCOMPARE(sizeof(qfloat16),sizeof(qfloat16(1.f)-qfloat16(1.f)));
QCOMPARE(sizeof(qfloat16),sizeof(qfloat16(1.f)*qfloat16(1.f)));
QCOMPARE(sizeof(qfloat16),sizeof(qfloat16(1.f)/qfloat16(1.f)));
QCOMPARE(sizeof(float),sizeof(1.f+qfloat16(1.f)));
QCOMPARE(sizeof(float),sizeof(1.f-qfloat16(1.f)));
QCOMPARE(sizeof(float),sizeof(1.f*qfloat16(1.f)));
QCOMPARE(sizeof(float),sizeof(1.f/qfloat16(1.f)));
QCOMPARE(sizeof(float),sizeof(qfloat16(1.f)+1.f));
QCOMPARE(sizeof(float),sizeof(qfloat16(1.f)-1.f));
QCOMPARE(sizeof(float),sizeof(qfloat16(1.f)*1.f));
QCOMPARE(sizeof(float),sizeof(qfloat16(1.f)/1.f));
QCOMPARE(sizeof(double),sizeof(1.+qfloat16(1.f)));
QCOMPARE(sizeof(double),sizeof(1.-qfloat16(1.f)));
QCOMPARE(sizeof(double),sizeof(1.*qfloat16(1.f)));
QCOMPARE(sizeof(double),sizeof(1./qfloat16(1.f)));
QCOMPARE(sizeof(double),sizeof(qfloat16(1.f)+1.));
QCOMPARE(sizeof(double),sizeof(qfloat16(1.f)-1.));
QCOMPARE(sizeof(double),sizeof(qfloat16(1.f)*1.));
QCOMPARE(sizeof(double),sizeof(qfloat16(1.f)/1.));
QCOMPARE(sizeof(long double),sizeof((long double)(1.)+qfloat16(1.f)));
QCOMPARE(sizeof(long double),sizeof((long double)(1.)-qfloat16(1.f)));
QCOMPARE(sizeof(long double),sizeof((long double)(1.)*qfloat16(1.f)));
QCOMPARE(sizeof(long double),sizeof((long double)(1.)/qfloat16(1.f)));
QCOMPARE(sizeof(long double),sizeof(qfloat16(1.f)+(long double)(1.)));
QCOMPARE(sizeof(long double),sizeof(qfloat16(1.f)-(long double)(1.)));
QCOMPARE(sizeof(long double),sizeof(qfloat16(1.f)*(long double)(1.)));
QCOMPARE(sizeof(long double),sizeof(qfloat16(1.f)/(long double)(1.)));
QCOMPARE(sizeof(double),sizeof(1+qfloat16(1.f)));
QCOMPARE(sizeof(double),sizeof(1-qfloat16(1.f)));
QCOMPARE(sizeof(double),sizeof(1*qfloat16(1.f)));
QCOMPARE(sizeof(double),sizeof(1/qfloat16(1.f)));
QCOMPARE(sizeof(double),sizeof(qfloat16(1.f)+1));
QCOMPARE(sizeof(double),sizeof(qfloat16(1.f)-1));
QCOMPARE(sizeof(double),sizeof(qfloat16(1.f)*1));
QCOMPARE(sizeof(double),sizeof(qfloat16(1.f)/1));
}
QTEST_APPLESS_MAIN(tst_qfloat16)
#include "tst_qfloat16.moc"