diff --git a/src/internal/Loop.h b/src/internal/Loop.h index b68982ab7..27f53a31b 100644 --- a/src/internal/Loop.h +++ b/src/internal/Loop.h @@ -51,4 +51,4 @@ template class EiLoop<0, Rows> } }; -#endif //EI_LOOP_H +#endif // EI_LOOP_H diff --git a/src/internal/Matrix.h b/src/internal/Matrix.h index 19e3b313d..d20fd9214 100644 --- a/src/internal/Matrix.h +++ b/src/internal/Matrix.h @@ -27,6 +27,7 @@ #define EI_MATRIX_H #include "Util.h" +#include "Numeric.h" #include "Object.h" #include "MatrixRef.h" #include "MatrixStorage.h" diff --git a/src/internal/Numeric.h b/src/internal/Numeric.h new file mode 100644 index 000000000..126993609 --- /dev/null +++ b/src/internal/Numeric.h @@ -0,0 +1,177 @@ + +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. Eigen itself is part of the KDE project. +// +// Copyright (C) 2006-2007 Benoit Jacob +// +// Eigen is free software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the Free Software +// Foundation; either version 2 or (at your option) any later version. +// +// Eigen 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 General Public License for more +// details. +// +// You should have received a copy of the GNU General Public License along +// with Eigen; if not, write to the Free Software Foundation, Inc., 51 +// Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. +// +// As a special exception, if other files instantiate templates or use macros +// or functions from this file, or you compile this file and link it +// with other works to produce a work based on this file, this file does not +// by itself cause the resulting work to be covered by the GNU General Public +// License. This exception does not invalidate any other reasons why a work +// based on this file might be covered by the GNU General Public License. + +#ifndef EI_TRAITS_H +#define EI_TRAITS_H + +template struct EiTraits; + +template<> struct EiTraits +{ + typedef int Real; + typedef double FloatingPoint; + typedef double RealFloatingPoint; + + static const int Epsilon = 0; + static const bool IsComplex = false; + static const bool HasFloatingPoint = false; + + static int real(const int& x) { return x; } + static int imag(const int& x) { EI_UNUSED(x); return 0; } + static int conj(const int& x) { return x; } + static double sqrt(const int& x) { return std::sqrt(static_cast(x)); } + static int abs(const int& x) { return std::abs(x); } + static int abs2(const int& x) { return x*x; } + static int random() + { + // "rand()%21" would be bad. always use the high-order bits, not the low-order bits. + // note: here (gcc 4.1) static_cast seems to round the nearest int. + // I don't know if that's part of the standard. + return -10 + static_cast(20.0 * (rand() / (RAND_MAX + 1.0))); + } +}; + +template<> struct EiTraits +{ + typedef float Real; + typedef float FloatingPoint; + typedef float RealFloatingPoint; + + static const float Epsilon; + static const bool IsComplex = false; + static const bool HasFloatingPoint = true; + + static float real(const float& x) { return x; } + static float imag(const float& x) { EI_UNUSED(x); return 0; } + static float conj(const float& x) { return x; } + static float sqrt(const float& x) { return std::sqrt(x); } + static float abs(const float& x) { return std::abs(x); } + static float abs2(const float& x) { return x*x; } + static float random() + { + return 20.0f * rand() / RAND_MAX - 10.0f; + } +}; + +const float EiTraits::Epsilon = 1e-5f; + +template<> struct EiTraits +{ + typedef double Real; + typedef double FloatingPoint; + typedef double RealFloatingPoint; + + static const double Epsilon; + static const bool IsComplex = false; + static const bool HasFloatingPoint = true; + + static double real(const double& x) { return x; } + static double imag(const double& x) { EI_UNUSED(x); return 0; } + static double conj(const double& x) { return x; } + static double sqrt(const double& x) { return std::sqrt(x); } + static double abs(const double& x) { return std::abs(x); } + static double abs2(const double& x) { return x*x; } + static double random() + { + return 20.0 * rand() / RAND_MAX - 10.0; + } +}; + +const double EiTraits::Epsilon = 1e-11; + +template struct EiTraits > +{ + typedef _Real Real; + typedef std::complex Complex; + typedef std::complex FloatingPoint; + typedef typename EiTraits::FloatingPoint RealFloatingPoint; + + static const Real Epsilon; + static const bool IsComplex = true; + static const bool HasFloatingPoint = EiTraits::HasFloatingPoint; + + static Real real(const Complex& x) { return std::real(x); } + static Real imag(const Complex& x) { return std::imag(x); } + static Complex conj(const Complex& x) { return std::conj(x); } + static FloatingPoint sqrt(const Complex& x) + { return std::sqrt(static_cast(x)); } + static RealFloatingPoint abs(const Complex& x) + { return std::abs(static_cast(x)); } + static Real abs2(const Complex& x) + { return std::real(x) * std::real(x) + std::imag(x) * std::imag(x); } + static Complex random() + { + return Complex(EiTraits::random(), EiTraits::random()); + } +}; + +template +const _Real EiTraits >::Epsilon + = EiTraits<_Real>::Epsilon; + +template typename EiTraits::Real EiReal(const T& x) +{ return EiTraits::real(x); } + +template typename EiTraits::Real EiImag(const T& x) +{ return EiTraits::imag(x); } + +template T EiConj(const T& x) +{ return EiTraits::conj(x); } + +template typename EiTraits::FloatingPoint EiSqrt(const T& x) +{ return EiTraits::sqrt(x); } + +template typename EiTraits::RealFloatingPoint EiAbs(const T& x) +{ return EiTraits::abs(x); } + +template typename EiTraits::Real EiAbs2(const T& x) +{ return EiTraits::abs2(x); } + +template T EiRandom() +{ return EiTraits::random(); } + +template bool EiNegligible(const T& a, const T& b) +{ + return(EiAbs(a) <= EiAbs(b) * EiTraits::Epsilon); +} + +template bool EiApprox(const T& a, const T& b) +{ + if(EiTraits::IsFloat) + return(EiAbs(a - b) <= std::min(EiAbs(a), EiAbs(b)) * EiTraits::Epsilon); + else + return(a == b); +} + +template bool EiLessThanOrApprox(const T& a, const T& b) +{ + if(EiTraits::IsFloat) + return(a < b || EiApprox(a, b)); + else + return(a <= b); +} + +#endif // EI_TRAITS_H diff --git a/test/main.h b/test/main.h index 1cdc781d7..06f295ece 100644 --- a/test/main.h +++ b/test/main.h @@ -47,4 +47,35 @@ class EigenTest : public QObject void testMatrixManip(); }; +template T TestEpsilon(); +template<> int TestEpsilon() { return 0; } +template<> float TestEpsilon() { return 1e-2f; } +template<> double TestEpsilon() { return 1e-4; } +template T TestEpsilon >() { return TestEpsilon(); } + +template bool TestNegligible(const T& a, const T& b) +{ + return(EiAbs(a) <= EiAbs(b) * TestEpsilon()); +} + +template bool TestApprox(const T& a, const T& b) +{ + if(EiTraits::IsFloat) + return(EiAbs(a - b) <= std::min(EiAbs(a), EiAbs(b)) * TestEpsilon()); + else + return(a == b); +} + +template bool TestLessThanOrApprox(const T& a, const T& b) +{ + if(EiTraits::IsFloat) + return(a < b || EiApprox(a, b)); + else + return(a <= b); +} + +#define QVERIFY_NEGLIGIBLE(a, b) QVERIFY(TestNegligible(a, b)) +#define QVERIFY_APPROX(a, b) QVERIFY(TestApprox(a, b)) +#define QVERIFY_LESS_THAN_OR_APPROX(a, b) QVERIFY(TestLessThanOrApprox(a, b)) + #endif // EI_TEST_MAIN_H