mirror of https://github.com/mosra/magnum.git
Browse Source
Fuzzy comparison is implemented only on floating-point types with type-specific epsilon, on integral types classic operator== is used. TypeTraits class is now extension of Math::TypeTraits (where it makes sense).pull/279/head
5 changed files with 232 additions and 17 deletions
@ -0,0 +1,60 @@ |
|||||||
|
/*
|
||||||
|
Copyright © 2010, 2011, 2012 Vladimír Vondruš <mosra@centrum.cz> |
||||||
|
|
||||||
|
This file is part of Magnum. |
||||||
|
|
||||||
|
Magnum is free software: you can redistribute it and/or modify |
||||||
|
it under the terms of the GNU Lesser General Public License version 3 |
||||||
|
only, as published by the Free Software Foundation. |
||||||
|
|
||||||
|
Magnum is distributed in the hope that it will be useful, |
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||||
|
GNU Lesser General Public License version 3 for more details. |
||||||
|
*/ |
||||||
|
|
||||||
|
#include "TypeTraitsTest.h" |
||||||
|
|
||||||
|
#include <QtTest/QTest> |
||||||
|
|
||||||
|
#include "TypeTraits.h" |
||||||
|
|
||||||
|
QTEST_APPLESS_MAIN(Magnum::Math::Test::TypeTraitsTest) |
||||||
|
|
||||||
|
namespace Magnum { namespace Math { namespace Test { |
||||||
|
|
||||||
|
void TypeTraitsTest::equalsIntegral() { |
||||||
|
_equalsIntegral<unsigned char>(); |
||||||
|
_equalsIntegral<char>(); |
||||||
|
_equalsIntegral<unsigned short>(); |
||||||
|
_equalsIntegral<short>(); |
||||||
|
_equalsIntegral<unsigned int>(); |
||||||
|
_equalsIntegral<int>(); |
||||||
|
_equalsIntegral<unsigned long int>(); |
||||||
|
_equalsIntegral<long int>(); |
||||||
|
_equalsIntegral<unsigned long long>(); |
||||||
|
_equalsIntegral<long long>(); |
||||||
|
} |
||||||
|
|
||||||
|
void TypeTraitsTest::equalsFloatingPoint() { |
||||||
|
_equalsFloatingPoint<float>(); |
||||||
|
_equalsFloatingPoint<double>(); |
||||||
|
} |
||||||
|
|
||||||
|
template<class T> void TypeTraitsTest::_equalsIntegral() { |
||||||
|
QVERIFY(TypeTraits<T>::equals(1, 1+TypeTraits<T>::epsilon())); |
||||||
|
QVERIFY(!TypeTraits<T>::equals(1, 2)); |
||||||
|
} |
||||||
|
|
||||||
|
template<class T> void TypeTraitsTest::_equalsFloatingPoint() { |
||||||
|
QVERIFY(TypeTraits<T>::equals(1.0f+TypeTraits<T>::epsilon()/2, 1.0f)); |
||||||
|
QVERIFY(!TypeTraits<T>::equals(1.0f+TypeTraits<T>::epsilon()*2, 1.0f)); |
||||||
|
|
||||||
|
QEXPECT_FAIL(0, "Comparing to infinity is broken", Continue); |
||||||
|
QVERIFY(TypeTraits<T>::equals(std::numeric_limits<T>::infinity(), |
||||||
|
std::numeric_limits<T>::infinity())); |
||||||
|
QVERIFY(!TypeTraits<T>::equals(std::numeric_limits<T>::quiet_NaN(), |
||||||
|
std::numeric_limits<T>::quiet_NaN())); |
||||||
|
} |
||||||
|
|
||||||
|
}}} |
||||||
@ -0,0 +1,36 @@ |
|||||||
|
#ifndef Magnum_Math_Test_TypeTraitsTest_h |
||||||
|
#define Magnum_Math_Test_TypeTraitsTest_h |
||||||
|
/*
|
||||||
|
Copyright © 2010, 2011, 2012 Vladimír Vondruš <mosra@centrum.cz> |
||||||
|
|
||||||
|
This file is part of Magnum. |
||||||
|
|
||||||
|
Magnum is free software: you can redistribute it and/or modify |
||||||
|
it under the terms of the GNU Lesser General Public License version 3 |
||||||
|
only, as published by the Free Software Foundation. |
||||||
|
|
||||||
|
Magnum is distributed in the hope that it will be useful, |
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||||
|
GNU Lesser General Public License version 3 for more details. |
||||||
|
*/ |
||||||
|
|
||||||
|
#include <QtCore/QObject> |
||||||
|
|
||||||
|
namespace Magnum { namespace Math { namespace Test { |
||||||
|
|
||||||
|
class TypeTraitsTest: public QObject { |
||||||
|
Q_OBJECT |
||||||
|
|
||||||
|
private slots: |
||||||
|
void equalsFloatingPoint(); |
||||||
|
void equalsIntegral(); |
||||||
|
|
||||||
|
private: |
||||||
|
template<class T> void _equalsFloatingPoint(); |
||||||
|
template<class T> void _equalsIntegral(); |
||||||
|
}; |
||||||
|
|
||||||
|
}}} |
||||||
|
|
||||||
|
#endif |
||||||
@ -0,0 +1,110 @@ |
|||||||
|
#ifndef Magnum_Math_TypeTraits_h |
||||||
|
#define Magnum_Math_TypeTraits_h |
||||||
|
/*
|
||||||
|
Copyright © 2010, 2011, 2012 Vladimír Vondruš <mosra@centrum.cz> |
||||||
|
|
||||||
|
This file is part of Magnum. |
||||||
|
|
||||||
|
Magnum is free software: you can redistribute it and/or modify |
||||||
|
it under the terms of the GNU Lesser General Public License version 3 |
||||||
|
only, as published by the Free Software Foundation. |
||||||
|
|
||||||
|
Magnum is distributed in the hope that it will be useful, |
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||||
|
GNU Lesser General Public License version 3 for more details. |
||||||
|
*/ |
||||||
|
|
||||||
|
/** @file
|
||||||
|
* @brief Class Magnum::Math::TypeTraits |
||||||
|
*/ |
||||||
|
|
||||||
|
#include <cmath> |
||||||
|
|
||||||
|
namespace Magnum { namespace Math { |
||||||
|
|
||||||
|
/**
|
||||||
|
@brief Traits class for numeric types |
||||||
|
|
||||||
|
Traits classes are usable for detecting type features at compile time without |
||||||
|
the need for repeated code such as method overloading or template |
||||||
|
specialization for given types. |
||||||
|
|
||||||
|
This class and class methods are specialized only for types where it makes |
||||||
|
sense, it has empty implementation for unknown types or types which don't |
||||||
|
support given feature, thus forcing the compilation stop with an error. |
||||||
|
*/ |
||||||
|
template<class T> struct TypeTraits { |
||||||
|
#ifdef DOXYGEN_GENERATING_OUTPUT |
||||||
|
/* Development note: the following values are implemented as inline
|
||||||
|
functions, not as static const variables, because the compiler will |
||||||
|
inline the return values instead of referencing to static data and |
||||||
|
unlike static const variables these functions can return floats. */ |
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Epsilon value for fuzzy compare |
||||||
|
* |
||||||
|
* Returns 0 for integer types and reasonably small value for |
||||||
|
* floating-point types. |
||||||
|
*/ |
||||||
|
constexpr inline static T epsilon(); |
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Fuzzy compare |
||||||
|
* |
||||||
|
* Uses equality for integer types and fuzzy compare for floating-point |
||||||
|
* types (using @ref epsilon value). |
||||||
|
*/ |
||||||
|
static bool equals(T a, T b); |
||||||
|
#endif |
||||||
|
}; |
||||||
|
|
||||||
|
/** @bug Infinity comparison! */ |
||||||
|
|
||||||
|
/**
|
||||||
|
* @todo Implement better fuzzy comparison algorithm, like at |
||||||
|
* http://floating-point-gui.de/errors/comparison/ or
|
||||||
|
* http://www.cygnus-software.com/papers/comparingfloats/comparingfloats.htm
|
||||||
|
*/ |
||||||
|
|
||||||
|
#ifndef DOXYGEN_GENERATING_OUTPUT |
||||||
|
template<class T> struct _TypeTraitsIntegral { |
||||||
|
constexpr inline static T epsilon() { return 0; } |
||||||
|
|
||||||
|
inline constexpr static bool equals(T a, T b) { |
||||||
|
return a == b; |
||||||
|
} |
||||||
|
}; |
||||||
|
template<> struct TypeTraits<unsigned char>: public _TypeTraitsIntegral<unsigned char> {}; |
||||||
|
template<> struct TypeTraits<char>: public _TypeTraitsIntegral<char> {}; |
||||||
|
|
||||||
|
template<> struct TypeTraits<unsigned short>: public _TypeTraitsIntegral<unsigned short> {}; |
||||||
|
template<> struct TypeTraits<short>: public _TypeTraitsIntegral<short> {}; |
||||||
|
|
||||||
|
template<> struct TypeTraits<unsigned int>: public _TypeTraitsIntegral<unsigned int> {}; |
||||||
|
template<> struct TypeTraits<int>: public _TypeTraitsIntegral<int> {}; |
||||||
|
|
||||||
|
/* long is 32 bits somewhere and 64 bits elsewhere, so it cannot be mapped to
|
||||||
|
any of them */ |
||||||
|
template<> struct TypeTraits<long unsigned int>: public _TypeTraitsIntegral<long unsigned int> {}; |
||||||
|
template<> struct TypeTraits<long int>: public _TypeTraitsIntegral<long int> {}; |
||||||
|
|
||||||
|
template<> struct TypeTraits<unsigned long long>: public _TypeTraitsIntegral<unsigned long long> {}; |
||||||
|
template<> struct TypeTraits<long long>: public _TypeTraitsIntegral<long long> {}; |
||||||
|
|
||||||
|
template<class T> struct _TypeTraitsFloatingPoint { |
||||||
|
inline static bool equals(T a, T b) { |
||||||
|
return std::abs(a - b) < TypeTraits<T>::epsilon(); |
||||||
|
} |
||||||
|
}; |
||||||
|
template<> struct TypeTraits<float>: public _TypeTraitsFloatingPoint<float> { |
||||||
|
constexpr inline static float epsilon() { return 1.0e-6f; } |
||||||
|
}; |
||||||
|
template<> struct TypeTraits<double>: public _TypeTraitsFloatingPoint<double> { |
||||||
|
constexpr inline static double epsilon() { return 1.0e-12; } |
||||||
|
}; |
||||||
|
#endif |
||||||
|
|
||||||
|
}} |
||||||
|
|
||||||
|
#endif |
||||||
Loading…
Reference in new issue