diff options
author | Benoit Jacob <jacob.benoit.1@gmail.com> | 2010-04-28 18:51:38 -0400 |
---|---|---|
committer | Benoit Jacob <jacob.benoit.1@gmail.com> | 2010-04-28 18:51:38 -0400 |
commit | e2775869588e1df2d19265eac5c167651168a414 (patch) | |
tree | 8ca0d2fdbc1f8945405fb3fd99c5634b60f3189f /Eigen/src | |
parent | 4f83d6ad1959f3c76cd5eb328ec65ced4ca4f339 (diff) |
Complete rework of global math functions and NumTraits.
* Now completely generic so all standard integer types (like char...) are supported.
** add unit test for that (integer_types).
* NumTraits does no longer inherit numeric_limits
* All math functions are now templated
* Better guard (static asserts) against using certain math functions on integer types.
Diffstat (limited to 'Eigen/src')
-rw-r--r-- | Eigen/src/Array/ArrayBase.h | 2 | ||||
-rw-r--r-- | Eigen/src/Array/GlobalFunctions.h | 44 | ||||
-rw-r--r-- | Eigen/src/Core/Dot.h | 2 | ||||
-rw-r--r-- | Eigen/src/Core/Functors.h | 16 | ||||
-rw-r--r-- | Eigen/src/Core/Fuzzy.h | 2 | ||||
-rw-r--r-- | Eigen/src/Core/IO.h | 6 | ||||
-rw-r--r-- | Eigen/src/Core/MathFunctions.h | 921 | ||||
-rw-r--r-- | Eigen/src/Core/NumTraits.h | 176 | ||||
-rw-r--r-- | Eigen/src/Core/SelfCwiseBinaryOp.h | 6 | ||||
-rw-r--r-- | Eigen/src/Core/util/StaticAssert.h | 5 | ||||
-rw-r--r-- | Eigen/src/Geometry/AlignedBox.h | 15 | ||||
-rw-r--r-- | Eigen/src/LU/Inverse.h | 4 |
12 files changed, 798 insertions, 401 deletions
diff --git a/Eigen/src/Array/ArrayBase.h b/Eigen/src/Array/ArrayBase.h index c507b7694..b835a57ad 100644 --- a/Eigen/src/Array/ArrayBase.h +++ b/Eigen/src/Array/ArrayBase.h @@ -54,6 +54,8 @@ template<typename Derived> class ArrayBase #ifndef EIGEN_PARSED_BY_DOXYGEN /** The base class for a given storage type. */ typedef ArrayBase StorageBaseType; + + typedef ArrayBase Eigen_BaseClassForSpecializationOfGlobalMathFuncImpl; using ei_special_scalar_op_base<Derived,typename ei_traits<Derived>::Scalar, typename NumTraits<typename ei_traits<Derived>::Scalar>::Real>::operator*; diff --git a/Eigen/src/Array/GlobalFunctions.h b/Eigen/src/Array/GlobalFunctions.h index 33f00c2ba..0e42d0981 100644 --- a/Eigen/src/Array/GlobalFunctions.h +++ b/Eigen/src/Array/GlobalFunctions.h @@ -2,6 +2,7 @@ // for linear algebra. // // Copyright (C) 2010 Gael Guennebaud <g.gael@free.fr> +// Copyright (C) 2010 Benoit Jacob <jacob.benoit.1@gmail.com> // // Eigen is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -25,31 +26,46 @@ #ifndef EIGEN_GLOBAL_FUNCTIONS_H #define EIGEN_GLOBAL_FUNCTIONS_H -#define EIGEN_ARRAY_DECLARARE_GLOBAL_UNARY(NAME,FUNCTOR) \ +#define EIGEN_ARRAY_DECLARE_GLOBAL_STD_UNARY(NAME,FUNCTOR) \ template<typename Derived> \ inline const Eigen::CwiseUnaryOp<Eigen::FUNCTOR<typename Derived::Scalar>, Derived> \ NAME(const Eigen::ArrayBase<Derived>& x) { \ return x.derived(); \ } - + +#define EIGEN_ARRAY_DECLARE_GLOBAL_EIGEN_UNARY(NAME,FUNCTOR) \ + template<typename Derived> \ + struct NAME##_impl<ArrayBase<Derived> > \ + { \ + typedef const Eigen::CwiseUnaryOp<Eigen::FUNCTOR<typename Derived::Scalar>, Derived> retval; \ + static inline retval run(const Eigen::ArrayBase<Derived>& x) \ + { \ + return x.derived(); \ + } \ + }; + + namespace std { - EIGEN_ARRAY_DECLARARE_GLOBAL_UNARY(sin,ei_scalar_sin_op) - EIGEN_ARRAY_DECLARARE_GLOBAL_UNARY(cos,ei_scalar_cos_op) - EIGEN_ARRAY_DECLARARE_GLOBAL_UNARY(exp,ei_scalar_exp_op) - EIGEN_ARRAY_DECLARARE_GLOBAL_UNARY(log,ei_scalar_log_op) - EIGEN_ARRAY_DECLARARE_GLOBAL_UNARY(abs,ei_scalar_abs_op) - EIGEN_ARRAY_DECLARARE_GLOBAL_UNARY(sqrt,ei_scalar_sqrt_op) + EIGEN_ARRAY_DECLARE_GLOBAL_STD_UNARY(sin,ei_scalar_sin_op) + EIGEN_ARRAY_DECLARE_GLOBAL_STD_UNARY(cos,ei_scalar_cos_op) + EIGEN_ARRAY_DECLARE_GLOBAL_STD_UNARY(exp,ei_scalar_exp_op) + EIGEN_ARRAY_DECLARE_GLOBAL_STD_UNARY(log,ei_scalar_log_op) + EIGEN_ARRAY_DECLARE_GLOBAL_STD_UNARY(abs,ei_scalar_abs_op) + EIGEN_ARRAY_DECLARE_GLOBAL_STD_UNARY(sqrt,ei_scalar_sqrt_op) } namespace Eigen { - EIGEN_ARRAY_DECLARARE_GLOBAL_UNARY(ei_sin,ei_scalar_sin_op) - EIGEN_ARRAY_DECLARARE_GLOBAL_UNARY(ei_cos,ei_scalar_cos_op) - EIGEN_ARRAY_DECLARARE_GLOBAL_UNARY(ei_exp,ei_scalar_exp_op) - EIGEN_ARRAY_DECLARARE_GLOBAL_UNARY(ei_log,ei_scalar_log_op) - EIGEN_ARRAY_DECLARARE_GLOBAL_UNARY(ei_abs,ei_scalar_abs_op) - EIGEN_ARRAY_DECLARARE_GLOBAL_UNARY(ei_sqrt,ei_scalar_sqrt_op) + EIGEN_ARRAY_DECLARE_GLOBAL_EIGEN_UNARY(ei_sin,ei_scalar_sin_op) + EIGEN_ARRAY_DECLARE_GLOBAL_EIGEN_UNARY(ei_cos,ei_scalar_cos_op) + EIGEN_ARRAY_DECLARE_GLOBAL_EIGEN_UNARY(ei_exp,ei_scalar_exp_op) + EIGEN_ARRAY_DECLARE_GLOBAL_EIGEN_UNARY(ei_log,ei_scalar_log_op) + EIGEN_ARRAY_DECLARE_GLOBAL_EIGEN_UNARY(ei_abs,ei_scalar_abs_op) + EIGEN_ARRAY_DECLARE_GLOBAL_EIGEN_UNARY(ei_abs2,ei_scalar_abs2_op) + EIGEN_ARRAY_DECLARE_GLOBAL_EIGEN_UNARY(ei_sqrt,ei_scalar_sqrt_op) } +// TODO: cleanly disable those functions that are not suppored on Array (ei_real_ref, ei_random, ei_isApprox...) + #endif // EIGEN_GLOBAL_FUNCTIONS_H diff --git a/Eigen/src/Core/Dot.h b/Eigen/src/Core/Dot.h index fbdc67bd3..4bd81872d 100644 --- a/Eigen/src/Core/Dot.h +++ b/Eigen/src/Core/Dot.h @@ -161,7 +161,7 @@ bool MatrixBase<Derived>::isUnitary(RealScalar prec) const typename Derived::Nested nested(derived()); for(int i = 0; i < cols(); ++i) { - if(!ei_isApprox(nested.col(i).squaredNorm(), static_cast<Scalar>(1), prec)) + if(!ei_isApprox(nested.col(i).squaredNorm(), static_cast<RealScalar>(1), prec)) return false; for(int j = 0; j < i; ++j) if(!ei_isMuchSmallerThan(nested.col(i).dot(nested.col(j)), static_cast<Scalar>(1), prec)) diff --git a/Eigen/src/Core/Functors.h b/Eigen/src/Core/Functors.h index d02633cb8..bdceb9bb5 100644 --- a/Eigen/src/Core/Functors.h +++ b/Eigen/src/Core/Functors.h @@ -180,7 +180,7 @@ struct ei_functor_traits<ei_scalar_quotient_op<Scalar> > { Cost = 2 * NumTraits<Scalar>::MulCost, PacketAccess = ei_packet_traits<Scalar>::size>1 #if (defined EIGEN_VECTORIZE) - && NumTraits<Scalar>::HasFloatingPoint + && !NumTraits<Scalar>::IsInteger #endif }; }; @@ -384,7 +384,7 @@ template<typename Scalar1,typename Scalar2> struct ei_functor_traits<ei_scalar_multiple2_op<Scalar1,Scalar2> > { enum { Cost = NumTraits<Scalar1>::MulCost, PacketAccess = false }; }; -template<typename Scalar, bool HasFloatingPoint> +template<typename Scalar, bool IsInteger> struct ei_scalar_quotient1_impl { typedef typename ei_packet_traits<Scalar>::type PacketScalar; // FIXME default copy constructors seems bugged with std::complex<> @@ -396,11 +396,11 @@ struct ei_scalar_quotient1_impl { const Scalar m_other; }; template<typename Scalar> -struct ei_functor_traits<ei_scalar_quotient1_impl<Scalar,true> > +struct ei_functor_traits<ei_scalar_quotient1_impl<Scalar,false> > { enum { Cost = NumTraits<Scalar>::MulCost, PacketAccess = ei_packet_traits<Scalar>::size>1 }; }; template<typename Scalar> -struct ei_scalar_quotient1_impl<Scalar,false> { +struct ei_scalar_quotient1_impl<Scalar,true> { // FIXME default copy constructors seems bugged with std::complex<> EIGEN_STRONG_INLINE ei_scalar_quotient1_impl(const ei_scalar_quotient1_impl& other) : m_other(other.m_other) { } EIGEN_STRONG_INLINE ei_scalar_quotient1_impl(const Scalar& other) : m_other(other) {} @@ -408,7 +408,7 @@ struct ei_scalar_quotient1_impl<Scalar,false> { typename ei_makeconst<typename NumTraits<Scalar>::Nested>::type m_other; }; template<typename Scalar> -struct ei_functor_traits<ei_scalar_quotient1_impl<Scalar,false> > +struct ei_functor_traits<ei_scalar_quotient1_impl<Scalar,true> > { enum { Cost = 2 * NumTraits<Scalar>::MulCost, PacketAccess = false }; }; /** \internal @@ -420,13 +420,13 @@ struct ei_functor_traits<ei_scalar_quotient1_impl<Scalar,false> > * \sa class CwiseUnaryOp, MatrixBase::operator/ */ template<typename Scalar> -struct ei_scalar_quotient1_op : ei_scalar_quotient1_impl<Scalar, NumTraits<Scalar>::HasFloatingPoint > { +struct ei_scalar_quotient1_op : ei_scalar_quotient1_impl<Scalar, NumTraits<Scalar>::IsInteger > { EIGEN_STRONG_INLINE ei_scalar_quotient1_op(const Scalar& other) - : ei_scalar_quotient1_impl<Scalar, NumTraits<Scalar>::HasFloatingPoint >(other) {} + : ei_scalar_quotient1_impl<Scalar, NumTraits<Scalar>::IsInteger >(other) {} }; template<typename Scalar> struct ei_functor_traits<ei_scalar_quotient1_op<Scalar> > -: ei_functor_traits<ei_scalar_quotient1_impl<Scalar, NumTraits<Scalar>::HasFloatingPoint> > +: ei_functor_traits<ei_scalar_quotient1_impl<Scalar, NumTraits<Scalar>::IsInteger> > {}; // nullary functors diff --git a/Eigen/src/Core/Fuzzy.h b/Eigen/src/Core/Fuzzy.h index dfa042377..432da4288 100644 --- a/Eigen/src/Core/Fuzzy.h +++ b/Eigen/src/Core/Fuzzy.h @@ -26,6 +26,8 @@ #ifndef EIGEN_FUZZY_H #define EIGEN_FUZZY_H +// TODO support small integer types properly i.e. do exact compare on coeffs --- taking a HS norm is guaranteed to cause integer overflow. + #ifndef EIGEN_LEGACY_COMPARES /** \returns \c true if \c *this is approximately equal to \a other, within the precision diff --git a/Eigen/src/Core/IO.h b/Eigen/src/Core/IO.h index c98742246..853506288 100644 --- a/Eigen/src/Core/IO.h +++ b/Eigen/src/Core/IO.h @@ -153,13 +153,13 @@ std::ostream & ei_print_matrix(std::ostream & s, const Derived& _m, const IOForm } else if(fmt.precision == FullPrecision) { - if (NumTraits<Scalar>::HasFloatingPoint) + if (NumTraits<Scalar>::IsInteger) { - explicit_precision = ei_significant_decimals_impl<Scalar>::run(); + explicit_precision = 0; } else { - explicit_precision = 0; + explicit_precision = ei_significant_decimals_impl<Scalar>::run(); } } else diff --git a/Eigen/src/Core/MathFunctions.h b/Eigen/src/Core/MathFunctions.h index 4a21ec975..d32233f91 100644 --- a/Eigen/src/Core/MathFunctions.h +++ b/Eigen/src/Core/MathFunctions.h @@ -1,7 +1,7 @@ // This file is part of Eigen, a lightweight C++ template library // for linear algebra. // -// Copyright (C) 2006-2009 Benoit Jacob <jacob.benoit.1@gmail.com> +// Copyright (C) 2006-2010 Benoit Jacob <jacob.benoit.1@gmail.com> // // Eigen is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -25,330 +25,739 @@ #ifndef EIGEN_MATHFUNCTIONS_H #define EIGEN_MATHFUNCTIONS_H -template<typename T> inline T ei_random(T a, T b); -template<typename T> inline T ei_random(); -template<typename T> inline T ei_random_amplitude() +template<typename T, typename dummy = void> +struct ei_global_math_functions_filtering_base { - if(NumTraits<T>::HasFloatingPoint) return static_cast<T>(1); - else return static_cast<T>(10); -} + typedef T type; +}; -template<typename T> inline typename NumTraits<T>::Real ei_hypot(T x, T y) +template<typename T> struct ei_always_void { typedef void type; }; + +template<typename T> +struct ei_global_math_functions_filtering_base + <T, + typename ei_always_void<typename T::Eigen_BaseClassForSpecializationOfGlobalMathFuncImpl>::type + > { - typedef typename NumTraits<T>::Real RealScalar; - RealScalar _x = ei_abs(x); - RealScalar _y = ei_abs(y); - T p = std::max(_x, _y); - T q = std::min(_x, _y); - T qp = q/p; - return p * ei_sqrt(T(1) + qp*qp); -} + typedef typename T::Eigen_BaseClassForSpecializationOfGlobalMathFuncImpl type; +}; + +#define EIGEN_MFIMPL(func, scalar) ei_##func##_impl<typename ei_global_math_functions_filtering_base<scalar>::type> -// the point of wrapping these casts in this helper template struct is to allow users to specialize it to custom types -// that may not have the needed conversion operators (especially as c++98 doesn't have explicit conversion operators). +/**************************************************************************** +* Implementation of ei_real * +****************************************************************************/ -template<typename OldType, typename NewType> struct ei_cast_impl +template<typename Scalar> +struct ei_real_impl { - static inline NewType run(const OldType& x) + typedef typename NumTraits<Scalar>::Real RealScalar; + typedef RealScalar retval; + static inline RealScalar run(const Scalar& x) { - return static_cast<NewType>(x); - } + return x; + }; }; -template<typename OldType, typename NewType> inline NewType ei_cast(const OldType& x) +template<typename RealScalar> +struct ei_real_impl<std::complex<RealScalar> > { - return ei_cast_impl<OldType, NewType>::run(x); + typedef RealScalar retval; + static inline RealScalar run(const std::complex<RealScalar>& x) + { + return std::real(x); + }; +}; + +template<typename Scalar> +inline typename ei_real_impl<Scalar>::retval ei_real(const Scalar& x) +{ + return ei_real_impl<Scalar>::run(x); } +/**************************************************************************** +* Implementation of ei_imag * +****************************************************************************/ -/************** -*** int *** -**************/ - -inline int ei_real(int x) { return x; } -inline int& ei_real_ref(int& x) { return x; } -inline int ei_imag(int) { return 0; } -inline int ei_conj(int x) { return x; } -inline int ei_abs(int x) { return std::abs(x); } -inline int ei_abs2(int x) { return x*x; } -inline int ei_sqrt(int) { ei_assert(false); return 0; } -inline int ei_exp(int) { ei_assert(false); return 0; } -inline int ei_log(int) { ei_assert(false); return 0; } -inline int ei_sin(int) { ei_assert(false); return 0; } -inline int ei_cos(int) { ei_assert(false); return 0; } -inline int ei_atan2(int, int) { ei_assert(false); return 0; } -inline int ei_pow(int x, int y) -{ - int res = 1; - if(y < 0) return 0; - if(y & 1) res *= x; - y >>= 1; - while(y) - { - x *= x; - if(y&1) res *= x; - y >>= 1; - } - return res; -} +template<typename Scalar> +struct ei_imag_impl +{ + typedef typename NumTraits<Scalar>::Real RealScalar; + typedef RealScalar retval; + static inline RealScalar run(const Scalar&) + { + return RealScalar(0); + }; +}; -template<> inline int ei_random(int a, int b) +template<typename RealScalar> +struct ei_imag_impl<std::complex<RealScalar> > { - // We can't just do rand()%n as only the high-order bits are really random - return a + static_cast<int>((b-a+1) * (std::rand() / (RAND_MAX + 1.0))); -} -template<> inline int ei_random() + typedef RealScalar retval; + static inline RealScalar run(const std::complex<RealScalar>& x) + { + return std::imag(x); + }; +}; + +template<typename Scalar> +inline typename ei_imag_impl<Scalar>::retval ei_imag(const Scalar& x) { - return ei_random<int>(-ei_random_amplitude<int>(), ei_random_amplitude<int>()); + return ei_imag_impl<Scalar>::run(x); } -inline bool ei_isMuchSmallerThan(int a, int, int = NumTraits<int>::dummy_precision()) + +/**************************************************************************** +* Implementation of ei_real_ref * +****************************************************************************/ + +template<typename Scalar> +struct ei_real_ref_impl { - return a == 0; -} -inline bool ei_isApprox(int a, int b, int = NumTraits<int>::dummy_precision()) + typedef typename NumTraits<Scalar>::Real RealScalar; + static inline RealScalar& run(Scalar& x) + { + return reinterpret_cast<RealScalar*>(&x)[0]; + }; + static inline const RealScalar& run(const Scalar& x) + { + return reinterpret_cast<const RealScalar*>(&x)[0]; + }; +}; + +template<typename Scalar> +inline const typename NumTraits<Scalar>::Real& ei_real_ref(const Scalar& x) { - return a == b; + return ei_real_ref_impl<Scalar>::run(x); } -inline bool ei_isApproxOrLessThan(int a, int b, int = NumTraits<int>::dummy_precision()) + +template<typename Scalar> +inline typename NumTraits<Scalar>::Real& ei_real_ref(Scalar& x) { - return a <= b; + return ei_real_ref_impl<Scalar>::run(x); } -/************** -*** float *** -**************/ - -inline float ei_real(float x) { return x; } -inline float& ei_real_ref(float& x) { return x; } -inline float ei_imag(float) { return 0.f; } -inline float ei_conj(float x) { return x; } -inline float ei_abs(float x) { return std::abs(x); } -inline float ei_abs2(float x) { return x*x; } -inline float ei_norm1(float x) { return ei_abs(x); } -inline float ei_sqrt(float x) { return std::sqrt(x); } -inline float ei_exp(float x) { return std::exp(x); } -inline float ei_log(float x) { return std::log(x); } -inline float ei_sin(float x) { return std::sin(x); } -inline float ei_cos(float x) { return std::cos(x); } -inline float ei_atan2(float y, float x) { return std::atan2(y,x); } -inline float ei_pow(float x, float y) { return std::pow(x, y); } - -template<> inline float ei_random(float a, float b) -{ -#ifdef EIGEN_NICE_RANDOM - int i; - do { i = ei_random<int>(256*int(a),256*int(b)); - } while(i==0); - return float(i)/256.f; -#else - return a + (b-a) * float(std::rand()) / float(RAND_MAX); -#endif -} -template<> inline float ei_random() +/**************************************************************************** +* Implementation of ei_imag_ref * +****************************************************************************/ + +template<typename Scalar, bool IsComplex> +struct ei_imag_ref_default_impl { - return ei_random<float>(-ei_random_amplitude<float>(), ei_random_amplitude<float>()); -} -inline bool ei_isMuchSmallerThan(float a, float b, float prec = NumTraits<float>::dummy_precision()) + typedef typename NumTraits<Scalar>::Real RealScalar; + static inline RealScalar& run(Scalar& x) + { + return reinterpret_cast<RealScalar*>(&x)[1]; + } + static inline const RealScalar& run(const Scalar& x) + { + return reinterpret_cast<RealScalar*>(&x)[1]; + } +}; + +template<typename Scalar> +struct ei_imag_ref_default_impl<Scalar, false> { - return ei_abs(a) <= ei_abs(b) * prec; -} -inline bool ei_isApprox(float a, float b, float prec = NumTraits<float>::dummy_precision()) + static inline Scalar run(Scalar&) + { + return Scalar(0); + } + static inline const Scalar run(const Scalar&) + { + return Scalar(0); + } +}; + +template<typename Scalar> +struct ei_imag_ref_impl : ei_imag_ref_default_impl<Scalar, NumTraits<Scalar>::IsComplex> {}; + +template<typename Scalar> +inline const typename NumTraits<Scalar>::Real& ei_imag_ref(const Scalar& x) { - return ei_abs(a - b) <= std::min(ei_abs(a), ei_abs(b)) * prec; + return ei_imag_ref_impl<Scalar>::run(x); } -inline bool ei_isApproxOrLessThan(float a, float b, float prec = NumTraits<float>::dummy_precision()) + +template<typename Scalar> +inline typename NumTraits<Scalar>::Real& ei_imag_ref(Scalar& x) { - return a <= b || ei_isApprox(a, b, prec); + return ei_imag_ref_impl<Scalar>::run(x); } -/************** -*** double *** -**************/ - -inline double ei_real(double x) { return x; } -inline double& ei_real_ref(double& x) { return x; } -inline double ei_imag(double) { return 0.; } -inline double ei_conj(double x) { return x; } -inline double ei_abs(double x) { return std::abs(x); } -inline double ei_abs2(double x) { return x*x; } -inline double ei_norm1(double x) { return ei_abs(x); } -inline double ei_sqrt(double x) { return std::sqrt(x); } -inline double ei_exp(double x) { return std::exp(x); } -inline double ei_log(double x) { return std::log(x); } -inline double ei_sin(double x) { return std::sin(x); } -inline double ei_cos(double x) { return std::cos(x); } -inline double ei_atan2(double y, double x) { return std::atan2(y,x); } -inline double ei_pow(double x, double y) { return std::pow(x, y); } - -template<> inline double ei_random(double a, double b) -{ -#ifdef EIGEN_NICE_RANDOM - int i; - do { i= ei_random<int>(256*int(a),256*int(b)); - } while(i==0); - return i/256.; -#else - return a + (b-a) * std::rand() / RAND_MAX; -#endif -} -template<> inline double ei_random() +/**************************************************************************** +* Implementation of ei_conj * +****************************************************************************/ + +template<typename Scalar> +struct ei_conj_impl { - return ei_random<double>(-ei_random_amplitude<double>(), ei_random_amplitude<double>()); -} -inline bool ei_isMuchSmallerThan(double a, double b, double prec = NumTraits<double>::dummy_precision()) + typedef Scalar retval; + static inline Scalar run(const Scalar& x) + { + return x; + }; +}; + +template<typename RealScalar> +struct ei_conj_impl<std::complex<RealScalar> > { - return ei_abs(a) <= ei_abs(b) * prec; -} -inline bool ei_isApprox(double a, double b, double prec = NumTraits<double>::dummy_precision()) + typedef std::complex<RealScalar> retval; + static inline std::complex<RealScalar> run(const std::complex<RealScalar>& x) + { + return std::conj(x); + }; +}; + +template<typename Scalar> +inline typename EIGEN_MFIMPL(conj, Scalar)::retval ei_conj(const Scalar& x) { - return ei_abs(a - b) <= std::min(ei_abs(a), ei_abs(b)) * prec; + return EIGEN_MFIMPL(conj, Scalar)::run(x); } -inline bool ei_isApproxOrLessThan(double a, double b, double prec = NumTraits<double>::dummy_precision()) + +/**************************************************************************** +* Implementation of ei_abs * +****************************************************************************/ + +template<typename Scalar> +struct ei_abs_impl +{ + typedef typename NumTraits<Scalar>::Real RealScalar; + typedef RealScalar retval; + static inline RealScalar run(const Scalar& x) + { + return std::abs(x); + }; +}; + +template<typename Scalar> +inline typename EIGEN_MFIMPL(abs, Scalar)::retval ei_abs(const Scalar& x) { - return a <= b || ei_isApprox(a, b, prec); + return EIGEN_MFIMPL(abs, Scalar)::run(x); } -/********************* -*** complex<float> *** -*********************/ - -inline float ei_real(const std::complex<float>& x) { return std::real(x); } -inline float ei_imag(const std::complex<float>& x) { return std::imag(x); } -inline float& ei_real_ref(std::complex<float>& x) { return reinterpret_cast<float*>(&x)[0]; } -inline float& ei_imag_ref(std::complex<float>& x) { return reinterpret_cast<float*>(&x)[1]; } -inline std::complex<float> ei_conj(const std::complex<float>& x) { return std::conj(x); } -inline float ei_abs(const std::complex<float>& x) { return std::abs(x); } -inline float ei_abs2(const std::complex<float>& x) { return std::norm(x); } -inline float ei_norm1(const std::complex<float> &x) { return(ei_abs(x.real()) + ei_abs(x.imag())); } -inline std::complex<float> ei_sqrt(std::complex<float>x) { return std::sqrt(x); } -inline std::complex<float> ei_exp(std::complex<float> x) { return std::exp(x); } -inline std::complex<float> ei_sin(std::complex<float> x) { return std::sin(x); } -inline std::complex<float> ei_cos(std::complex<float> x) { return std::cos(x); } -inline std::complex<float> ei_atan2(std::complex<float>, std::complex<float> ) { ei_assert(false); return 0.f; } - -template<> inline std::complex<float> ei_random() -{ - return std::complex<float>(ei_random<float>(), ei_random<float>()); +/**************************************************************************** +* Implementation of ei_abs2 * +****************************************************************************/ + +template<typename Scalar> +struct ei_abs2_impl +{ + typedef typename NumTraits<Scalar>::Real RealScalar; + typedef RealScalar retval; + static inline RealScalar run(const Scalar& x) + { + return x*x; + }; +}; + +template<typename RealScalar> +struct ei_abs2_impl<std::complex<RealScalar> > +{ + typedef RealScalar retval; + static inline RealScalar run(const std::complex<RealScalar>& x) + { + return std::norm(x); + }; +}; + +template<typename Scalar> +inline typename EIGEN_MFIMPL(abs2, Scalar)::retval ei_abs2(const Scalar& x) +{ + return EIGEN_MFIMPL(abs2, Scalar)::run(x); } -inline bool ei_isMuchSmallerThan(const std::complex<float>& a, const std::complex<float>& b, float prec = NumTraits<float>::dummy_precision()) + +/**************************************************************************** +* Implementation of ei_norm1 * +****************************************************************************/ + +template<typename Scalar> +struct ei_norm1_impl +{ + typedef typename NumTraits<Scalar>::Real RealScalar; + typedef RealScalar retval; + static inline RealScalar run(const Scalar& x) + { + return NumTraits<Scalar>::IsComplex + ? ei_abs(ei_real(x)) + ei_abs(ei_imag(x)) + : ei_abs(x); + }; +}; + +template<typename Scalar> +inline typename EIGEN_MFIMPL(norm1, Scalar)::retval ei_norm1(const Scalar& x) { - return ei_abs2(a) <= ei_abs2(b) * prec * prec; + return EIGEN_MFIMPL(norm1, Scalar)::run(x); } -inline bool ei_isMuchSmallerThan(const std::complex<float>& a, float b, float prec = NumTraits<float>::dummy_precision()) + +/**************************************************************************** +* Implementation of ei_hypot * +****************************************************************************/ + +template<typename Scalar> +struct ei_hypot_impl { - return ei_abs2(a) <= ei_abs2(b) * prec * prec; + typedef typename NumTraits<Scalar>::Real RealScalar; + typedef RealScalar retval; + static inline RealScalar run(const Scalar& x, const Scalar& y) + { + RealScalar _x = ei_abs(x); + RealScalar _y = ei_abs(y); + RealScalar p = std::max(_x, _y); + RealScalar q = std::min(_x, _y); + RealScalar qp = q/p; + return p * ei_sqrt(RealScalar(1) + qp*qp); + }; +}; + +template<typename Scalar> +inline typename EIGEN_MFIMPL(hypot, Scalar)::retval ei_hypot(const Scalar& x, const Scalar& y) +{ + return EIGEN_MFIMPL(hypot, Scalar)::run(x); } -inline bool ei_isApprox(const std::complex<float>& a, const std::complex<float>& b, float prec = NumTraits<float>::dummy_precision()) + +/**************************************************************************** +* Implementation of ei_cast * +****************************************************************************/ + +template<typename OldType, typename NewType> +struct ei_cast_impl +{ + typedef NewType retval; + static inline NewType run(const OldType& x) + { + return static_cast<NewType>(x); + } +}; + +template<typename OldType, typename NewType> +inline typename ei_cast_impl<OldType, NewType>::retval ei_cast(const OldType& x) { - return ei_isApprox(ei_real(a), ei_real(b), prec) - && ei_isApprox(ei_imag(a), ei_imag(b), prec); + return ei_cast_impl<OldType, NewType>::run(x); } -// ei_isApproxOrLessThan wouldn't make sense for complex numbers - -/********************** -*** complex<double> *** -**********************/ - -inline double ei_real(const std::complex<double>& x) { return std::real(x); } -inline double ei_imag(const std::complex<double>& x) { return std::imag(x); } -inline double& ei_real_ref(std::complex<double>& x) { return reinterpret_cast<double*>(&x)[0]; } -inline double& ei_imag_ref(std::complex<double>& x) { return reinterpret_cast<double*>(&x)[1]; } -inline std::complex<double> ei_conj(const std::complex<double>& x) { return std::conj(x); } -inline double ei_abs(const std::complex<double>& x) { return std::abs(x); } -inline double ei_abs2(const std::complex<double>& x) { return std::norm(x); } -inline double ei_norm1(const std::complex<double> &x) { return(ei_abs(x.real()) + ei_abs(x.imag())); } -inline std::complex<double> ei_sqrt(std::complex<double>x) { return std::sqrt(x); } -inline std::complex<double> ei_exp(std::complex<double> x) { return std::exp(x); } -inline std::complex<double> ei_sin(std::complex<double> x) { return std::sin(x); } -inline std::complex<double> ei_cos(std::complex<double> x) { return std::cos(x); } -inline std::complex<double> ei_atan2(std::complex<double>, std::complex<double>) { ei_assert(false); return 0.; } - -template<> inline std::complex<double> ei_random() -{ - return std::complex<double>(ei_random<double>(), ei_random<double>()); + +/**************************************************************************** +* Implementation of ei_sqrt * +****************************************************************************/ + +template<typename Scalar, bool IsInteger> +struct ei_sqrt_default_impl +{ + typedef Scalar retval; + static inline Scalar run(const Scalar& x) + { + return std::sqrt(x); + }; +}; + +template<typename Scalar> +struct ei_sqrt_default_impl<Scalar, true> +{ + typedef Scalar retval; + static inline Scalar run(const Scalar&) + { + EIGEN_STATIC_ASSERT_NON_INTEGER(Scalar) + return Scalar(0); + }; +}; + +template<typename Scalar> +struct ei_sqrt_impl : ei_sqrt_default_impl<Scalar, NumTraits<Scalar>::IsInteger> {}; + +template<typename Scalar> +inline typename EIGEN_MFIMPL(sqrt, Scalar)::retval ei_sqrt(const Scalar& x) +{ + return EIGEN_MFIMPL(sqrt, Scalar)::run(x); } -inline bool ei_isMuchSmallerThan(const std::complex<double>& a, const std::complex<double>& b, double prec = NumTraits<double>::dummy_precision()) + +/**************************************************************************** +* Implementation of ei_exp * +****************************************************************************/ + +template<typename Scalar, bool IsInteger> +struct ei_exp_default_impl +{ + typedef Scalar retval; + static inline Scalar run(const Scalar& x) + { + return std::exp(x); + }; +}; + +template<typename Scalar> +struct ei_exp_default_impl<Scalar, true> +{ + typedef Scalar retval; + static inline Scalar run(const Scalar&) + { + EIGEN_STATIC_ASSERT_NON_INTEGER(Scalar) + return Scalar(0); + }; +}; + +template<typename Scalar> +struct ei_exp_impl : ei_exp_default_impl<Scalar, NumTraits<Scalar>::IsInteger> {}; + +template<typename Scalar> +inline typename EIGEN_MFIMPL(exp, Scalar)::retval ei_exp(const Scalar& x) { - return ei_abs2(a) <= ei_abs2(b) * prec * prec; + return EIGEN_MFIMPL(exp, Scalar)::run(x); } -inline bool ei_isMuchSmallerThan(const std::complex<double>& a, double b, double prec = NumTraits<double>::dummy_precision()) + +/**************************************************************************** +* Implementation of ei_cos * +****************************************************************************/ + +template<typename Scalar, bool IsInteger> +struct ei_cos_default_impl { - return ei_abs2(a) <= ei_abs2(b) * prec * prec; + typedef Scalar retval; + static inline Scalar run(const Scalar& x) + { + return std::cos(x); + }; +}; + +template<typename Scalar> +struct ei_cos_default_impl<Scalar, true> +{ + typedef Scalar retval; + static inline Scalar run(const Scalar&) + { + EIGEN_STATIC_ASSERT_NON_INTEGER(Scalar) + return Scalar(0); + }; +}; + +template<typename Scalar> +struct ei_cos_impl : ei_cos_default_impl<Scalar, NumTraits<Scalar>::IsInteger> {}; + +template<typename Scalar> +inline typename EIGEN_MFIMPL(cos, Scalar)::retval ei_cos(const Scalar& x) +{ + return EIGEN_MFIMPL(cos, Scalar)::run(x); } -inline bool ei_isApprox(const std::complex<double>& a, const std::complex<double>& b, double prec = NumTraits<double>::dummy_precision()) + +/**************************************************************************** +* Implementation of ei_sin * +****************************************************************************/ + +template<typename Scalar, bool IsInteger> +struct ei_sin_default_impl +{ + typedef Scalar retval; + static inline Scalar run(const Scalar& x) + { + return std::sin(x); + }; +}; + +template<typename Scalar> +struct ei_sin_default_impl<Scalar, true> { - return ei_isApprox(ei_real(a), ei_real(b), prec) - && ei_isApprox(ei_imag(a), ei_imag(b), prec); + typedef Scalar retval; + static inline Scalar run(const Scalar&) + { + EIGEN_STATIC_ASSERT_NON_INTEGER(Scalar) + return Scalar(0); + }; +}; + +template<typename Scalar> +struct ei_sin_impl : ei_sin_default_impl<Scalar, NumTraits<Scalar>::IsInteger> {}; + +template<typename Scalar> +inline typename EIGEN_MFIMPL(sin, Scalar)::retval ei_sin(const Scalar& x) +{ + return EIGEN_MFIMPL(sin, Scalar)::run(x); } -// ei_isApproxOrLessThan wouldn't make sense for complex numbers - - -/****************** -*** long double *** -******************/ - -inline long double ei_real(long double x) { return x; } -inline long double& ei_real_ref(long double& x) { return x; } -inline long double ei_imag(long double) { return 0.; } -inline long double ei_conj(long double x) { return x; } -inline long double ei_abs(long double x) { return std::abs(x); } -inline long double ei_abs2(long double x) { return x*x; } -inline long double ei_sqrt(long double x) { return std::sqrt(x); } -inline long double ei_exp(long double x) { return std::exp(x); } -inline long double ei_log(long double x) { return std::log(x); } -inline long double ei_sin(long double x) { return std::sin(x); } -inline long double ei_cos(long double x) { return std::cos(x); } -inline long double ei_atan2(long double y, long double x) { return std::atan2(y,x); } -inline long double ei_pow(long double x, long double y) { return std::pow(x, y); } - -template<> inline long double ei_random(long double a, long double b) -{ - return ei_random<double>(static_cast<double>(a),static_cast<double>(b)); + +/**************************************************************************** +* Implementation of ei_log * +****************************************************************************/ + +template<typename Scalar, bool IsInteger> +struct ei_log_default_impl +{ + typedef Scalar retval; + static inline Scalar run(const Scalar& x) + { + return std::log(x); + }; +}; + +template<typename Scalar> +struct ei_log_default_impl<Scalar, true> +{ + typedef Scalar retval; + static inline Scalar run(const Scalar&) + { + EIGEN_STATIC_ASSERT_NON_INTEGER(Scalar) + return Scalar(0); + }; +}; + +template<typename Scalar> +struct ei_log_impl : ei_log_default_impl<Scalar, NumTraits<Scalar>::IsInteger> {}; + +template<typename Scalar> +inline typename EIGEN_MFIMPL(log, Scalar)::retval ei_log(const Scalar& x) +{ + return EIGEN_MFIMPL(log, Scalar)::run(x); } -template<> inline long double ei_random() + +/**************************************************************************** +* Implementation of ei_atan2 * +****************************************************************************/ + +template<typename Scalar, bool IsInteger> +struct ei_atan2_default_impl { - return ei_random<double>(-ei_random_amplitude<double>(), ei_random_amplitude<double>()); + typedef Scalar retval; + static inline Scalar run(const Scalar& x, const Scalar& y) + { + return std::atan2(x, y); + }; +}; + +template<typename Scalar> +struct ei_atan2_default_impl<Scalar, true> +{ + typedef Scalar retval; + static inline Scalar run(const Scalar&, const Scalar&) + { + EIGEN_STATIC_ASSERT_NON_INTEGER(Scalar) + return Scalar(0); + }; +}; + +template<typename Scalar> +struct ei_atan2_impl : ei_atan2_default_impl<Scalar, NumTraits<Scalar>::IsInteger> {}; + +template<typename Scalar> +inline typename EIGEN_MFIMPL(atan2, Scalar)::retval ei_atan2(const Scalar& x, const Scalar& y) +{ + return EIGEN_MFIMPL(atan2, Scalar)::run(x, y); } -inline bool ei_isMuchSmallerThan(long double a, long double b, long double prec = NumTraits<long double>::dummy_precision()) + +/**************************************************************************** +* Implementation of ei_pow * +****************************************************************************/ + +template<typename Scalar, bool IsInteger> +struct ei_pow_default_impl +{ + typedef Scalar retval; + static inline Scalar run(const Scalar& x, const Scalar& y) + { + return std::pow(x, y); + }; +}; + +template<typename Scalar> +struct ei_pow_default_impl<Scalar, true> +{ + typedef Scalar retval; + static inline Scalar run(Scalar x, Scalar y) + { + int res = 1; + if(NumTraits<Scalar>::IsSigned) ei_assert(y >= 0); + if(y & 1) res *= x; + y >>= 1; + while(y) + { + x *= x; + if(y&1) res *= x; + y >>= 1; + } + return res; + }; +}; + +template<typename Scalar> +struct ei_pow_impl : ei_pow_default_impl<Scalar, NumTraits<Scalar>::IsInteger> {}; + +template<typename Scalar> +inline typename EIGEN_MFIMPL(pow, Scalar)::retval ei_pow(const Scalar& x, const Scalar& y) { - return ei_abs(a) <= ei_abs(b) * prec; + return EIGEN_MFIMPL(pow, Scalar)::run(x, y); } -inline bool ei_isApprox(long double a, long double b, long double prec = NumTraits<long double>::dummy_precision()) + +/**************************************************************************** +* Implementation of ei_random * +****************************************************************************/ + +template<typename Scalar, + bool IsComplex, + bool IsInteger> +struct ei_random_default_impl {}; + +template<typename Scalar> +struct ei_random_impl : ei_random_default_impl<Scalar, NumTraits<Scalar>::IsComplex, NumTraits<Scalar>::IsInteger> {}; + +template<typename Scalar> inline typename EIGEN_MFIMPL(random, Scalar)::retval ei_random(const Scalar& x, const Scalar& y); +template<typename Scalar> inline typename EIGEN_MFIMPL(random, Scalar)::retval ei_random(); + +template<typename Scalar> +struct ei_random_default_impl<Scalar, false, false> +{ + typedef Scalar retval; + static inline Scalar run(const Scalar& x, const Scalar& y) + { + return x + (y-x) * Scalar(std::rand()) / float(RAND_MAX); + }; + static inline Scalar run() + { + return run(Scalar(NumTraits<Scalar>::IsSigned ? -1 : 0), Scalar(1)); + }; +}; + +template<typename Scalar> +struct ei_random_default_impl<Scalar, false, true> +{ + typedef Scalar retval; + static inline Scalar run(const Scalar& x, const Scalar& y) + { + return x + Scalar((y-x+1) * (std::rand() / (RAND_MAX + typename NumTraits<Scalar>::NonInteger(1)))); + }; + static inline Scalar run() + { + return run(Scalar(NumTraits<Scalar>::IsSigned ? -10 : 0), Scalar(10)); + }; +}; + +template<typename Scalar> +struct ei_random_default_impl<Scalar, true, false> +{ + typedef Scalar retval; + static inline Scalar run(const Scalar& x, const Scalar& y) + { + return Scalar(ei_random(ei_real(x), ei_real(y)), + ei_random(ei_imag(x), ei_imag(y))); + }; + static inline Scalar run() + { + typedef typename NumTraits<Scalar>::Real RealScalar; + return Scalar(ei_random<RealScalar>(), ei_random<RealScalar>()); + }; +}; + +template<typename Scalar> +inline typename EIGEN_MFIMPL(random, Scalar)::retval ei_random(const Scalar& x, const Scalar& y) { - return ei_abs(a - b) <= std::min(ei_abs(a), ei_abs(b)) * prec; + return EIGEN_MFIMPL(random, Scalar)::run(x, y); } -inline bool ei_isApproxOrLessThan(long double a, long double b, long double prec = NumTraits<long double>::dummy_precision()) + +template<typename Scalar> +inline typename EIGEN_MFIMPL(random, Scalar)::retval ei_random() { - return a <= b || ei_isApprox(a, b, prec); + return EIGEN_MFIMPL(random, Scalar)::run(); } -/************** -*** bool *** -**************/ +/**************************************************************************** +* Implementation of fuzzy comparisons * +****************************************************************************/ -inline bool ei_real(bool x) { return x; } -inline bool& ei_real_ref(bool& x) { return x; } -inline bool ei_imag(bool) { return 0; } -inline bool ei_conj(bool x) { return x; } -inline bool ei_abs(bool x) { return x; } -inline bool ei_abs2(bool x) { return x; } -inline bool ei_sqrt(bool x) { return x; } +template<typename Scalar, + bool IsComplex, + bool IsInteger> +struct ei_scalar_fuzzy_default_impl {}; -template<> inline bool ei_random() +template<typename Scalar> +struct ei_scalar_fuzzy_default_impl<Scalar, false, false> { - return (ei_random<int>(0,1) == 1); -} -inline bool ei_isMuchSmallerThan(bool a, bool, bool = NumTraits<bool>::dummy_precision()) + typedef typename NumTraits<Scalar>::Real RealScalar; + template<typename OtherScalar> + static inline bool isMuchSmallerThan(const Scalar& x, const OtherScalar& y, const RealScalar& prec) + { + return ei_abs(x) <= ei_abs(y) * prec; + } + static inline bool isApprox(const Scalar& x, const Scalar& y, const RealScalar& prec) + { + std::cout << " float" << std::endl; + return ei_abs(x - y) <= std::min(ei_abs(x), ei_abs(y)) * prec; + } + static inline bool isApproxOrLessThan(const Scalar& x, const Scalar& y, const RealScalar& prec) + { + return x <= y || isApprox(x, y, prec); + } +}; + +template<typename Scalar> +struct ei_scalar_fuzzy_default_impl<Scalar, false, true> { - return !a; + typedef typename NumTraits<Scalar>::Real RealScalar; + template<typename OtherScalar> + static inline bool isMuchSmallerThan(const Scalar& x, const Scalar&, const RealScalar&) + { + return x == Scalar(0); + } + static inline bool isApprox(const Scalar& x, const Scalar& y, const RealScalar&) + { + std::cout << " integer" << std::endl; + return x == y; + } + static inline bool isApproxOrLessThan(const Scalar& x, const Scalar& y, const RealScalar&) + { + return x <= y; + } +}; + +template<typename Scalar> +struct ei_scalar_fuzzy_default_impl<Scalar, true, false> +{ + typedef typename NumTraits<Scalar>::Real RealScalar; + template<typename OtherScalar> + static inline bool isMuchSmallerThan(const Scalar& x, const OtherScalar& y, const RealScalar& prec) + { + return ei_abs2(x) <= ei_abs2(y) * prec * prec; + } + static inline bool isApprox(const Scalar& x, const Scalar& y, const RealScalar& prec) + { + std::cout << " cplx" << std::endl; + return ei_abs2(x - y) <= std::min(ei_abs2(x), ei_abs2(y)) * prec * prec; + } +}; + +template<typename Scalar> +struct ei_scalar_fuzzy_impl : ei_scalar_fuzzy_default_impl<Scalar, NumTraits<Scalar>::IsComplex, NumTraits<Scalar>::IsInteger> {}; + +template<typename Scalar, typename OtherScalar> +inline bool ei_isMuchSmallerThan(const Scalar& x, const OtherScalar& y, + typename NumTraits<Scalar>::Real precision = NumTraits<Scalar>::dummy_precision()) +{ + return ei_scalar_fuzzy_impl<Scalar>::template isMuchSmallerThan<OtherScalar>(x, y, precision); } -inline bool ei_isApprox(bool a, bool b, bool = NumTraits<bool>::dummy_precision()) + +template<typename Scalar> +inline bool ei_isApprox(const Scalar& x, const Scalar& y, + typename NumTraits<Scalar>::Real precision = NumTraits<Scalar>::dummy_precision()) { - return a == b; + return ei_scalar_fuzzy_impl<Scalar>::isApprox(x, y, precision); } -inline bool ei_isApproxOrLessThan(bool a, bool b, bool = NumTraits<bool>::dummy_precision()) + +template<typename Scalar> +inline bool ei_isApproxOrLessThan(const Scalar& x, const Scalar& y, + typename NumTraits<Scalar>::Real precision = NumTraits<Scalar>::dummy_precision()) { - return int(a) <= int(b); + return ei_scalar_fuzzy_impl<Scalar>::isApproxOrLessThan(x, y, precision); } +/****************************************** +*** The special case of the bool type *** +******************************************/ + +template<> struct ei_random_impl<bool> +{ + static inline bool run() + { + return bool(ei_random<int>(0,1)); + }; +}; + +template<> struct ei_scalar_fuzzy_impl<bool> +{ + static inline bool isApprox(bool x, bool y, bool) + { + return x == y; + }; +}; + #endif // EIGEN_MATHFUNCTIONS_H diff --git a/Eigen/src/Core/NumTraits.h b/Eigen/src/Core/NumTraits.h index 37787b569..76bf8a58f 100644 --- a/Eigen/src/Core/NumTraits.h +++ b/Eigen/src/Core/NumTraits.h @@ -1,7 +1,7 @@ // This file is part of Eigen, a lightweight C++ template library // for linear algebra. // -// Copyright (C) 2006-2008 Benoit Jacob <jacob.benoit.1@gmail.com> +// Copyright (C) 2006-2010 Benoit Jacob <jacob.benoit.1@gmail.com> // // Eigen is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -27,157 +27,121 @@ /** \class NumTraits * - * \brief Holds some data about the various numeric (i.e. scalar) types allowed by Eigen. + * \brief Holds information about the various numeric (i.e. scalar) types allowed by Eigen. * - * \param T the numeric type about which this class provides data. Recall that Eigen allows - * only the following types for \a T: \c int, \c float, \c double, - * \c std::complex<float>, \c std::complex<double>, and \c long \c double (especially - * useful to enforce x87 arithmetics when SSE is the default). + * \param T the numeric type at hand * - * The provided data consists of everything that is supported by std::numeric_limits, plus: + * This class stores enums, typedefs and static methods giving information about a numeric type. + * + * The provided data consists of: * \li A typedef \a Real, giving the "real part" type of \a T. If \a T is already real, * then \a Real is just a typedef to \a T. If \a T is \c std::complex<U> then \a Real * is a typedef to \a U. - * \li A typedef \a FloatingPoint, giving the "floating-point type" of \a T. If \a T is - * \c int, then \a FloatingPoint is a typedef to \c double. Otherwise, \a FloatingPoint - * is a typedef to \a T. + * \li A typedef \a NonInteger, giving the type that should be used for operations producing non-integral values, + * such as quotients, square roots, etc. If \a T is a floating-point type, then this typedef just gives + * \a T again. Note however that many Eigen functions such as ei_sqrt simply refuse to + * take integers. Outside of a few cases, Eigen doesn't do automatic type promotion. Thus, this typedef is + * only intended as a helper for code that needs to explicitly promote types. + * \li A typedef \a Nested giving the type to use to nest a value inside of the expression tree. If you don't know what + * this means, just use \a T here. * \li An enum value \a IsComplex. It is equal to 1 if \a T is a \c std::complex * type, and to 0 otherwise. - * \li An enum \a HasFloatingPoint. It is equal to \c 0 if \a T is \c int, - * and to \c 1 otherwise. + * \li An enum value \a IsInteger. It is equal to \c 1 if \a T is an integer type such as \c int, + * and to \c 0 otherwise. + * \li Enum values ReadCost, AddCost and MulCost representing a rough estimate of the number of CPU cycles needed + * to by move / add / mul instructions respectively, assuming the data is already stored in CPU registers. + * Stay vague here. No need to do architecture-specific stuff. + * \li An enum value \a IsSigned. It is equal to \c 1 if \a T is a signed type and to 0 if \a T is unsigned. * \li An epsilon() function which, unlike std::numeric_limits::epsilon(), returns a \a Real instead of a \a T. - * \li A dummy_precision() function returning a weak epsilon value. It is mainly used by the fuzzy comparison operators. - * \li Two highest() and lowest() functions returning the highest and lowest possible values respectively. + * \li A dummy_precision() function returning a weak epsilon value. It is mainly used as a default + * value by the fuzzy comparison operators. + * \li highest() and lowest() functions returning the highest and lowest possible values respectively. */ -template<typename T> struct NumTraits; - -template<typename T> struct ei_default_float_numtraits - : std::numeric_limits<T> -{ - inline static T highest() { return std::numeric_limits<T>::max(); } - inline static T lowest() { return -std::numeric_limits<T>::max(); } -}; - -template<typename T> struct ei_default_integral_numtraits - : std::numeric_limits<T> -{ - inline static T dummy_precision() { return T(0); } - inline static T highest() { return std::numeric_limits<T>::max(); } - inline static T lowest() { return std::numeric_limits<T>::min(); } -}; -template<> struct NumTraits<int> - : ei_default_integral_numtraits<int> +template<typename T> struct GenericNumTraits { - typedef int Real; - typedef double FloatingPoint; - typedef int Nested; enum { + IsInteger = std::numeric_limits<T>::is_integer, + IsSigned = std::numeric_limits<T>::is_signed, IsComplex = 0, - HasFloatingPoint = 0, ReadCost = 1, AddCost = 1, MulCost = 1 }; + + typedef T Real; + typedef typename ei_meta_if< + IsInteger, + typename ei_meta_if<sizeof(T)<=2, float, double>::ret, + T + >::ret NonInteger; + typedef T Nested; + + inline static Real epsilon() { return std::numeric_limits<T>::epsilon(); } + inline static Real dummy_precision() + { + // make sure to override this for floating-point types + return Real(0); + } + inline static T highest() { return std::numeric_limits<T>::max(); } + inline static T lowest() { return std::numeric_limits<T>::min(); } }; +template<typename T> struct NumTraits : GenericNumTraits<T> +{}; + template<> struct NumTraits<float> - : ei_default_float_numtraits<float> + : GenericNumTraits<float> { - typedef float Real; - typedef float FloatingPoint; - typedef float Nested; - enum { - IsComplex = 0, - HasFloatingPoint = 1, - ReadCost = 1, - AddCost = 1, - MulCost = 1 - }; - inline static float dummy_precision() { return 1e-5f; } }; -template<> struct NumTraits<double> - : ei_default_float_numtraits<double> +template<> struct NumTraits<double> : GenericNumTraits<double> { - typedef double Real; - typedef double FloatingPoint; - typedef double Nested; - enum { - IsComplex = 0, - HasFloatingPoint = 1, - ReadCost = 1, - AddCost = 1, - MulCost = 1 - }; - inline static double dummy_precision() { return 1e-12; } }; +template<> struct NumTraits<long double> + : GenericNumTraits<long double> +{ + static inline long double dummy_precision() { return 1e-15l; } +}; + template<typename _Real> struct NumTraits<std::complex<_Real> > - : ei_default_float_numtraits<std::complex<_Real> > + : GenericNumTraits<std::complex<_Real> > { typedef _Real Real; - typedef std::complex<_Real> FloatingPoint; - typedef std::complex<_Real> Nested; enum { IsComplex = 1, - HasFloatingPoint = NumTraits<Real>::HasFloatingPoint, ReadCost = 2, AddCost = 2 * NumTraits<Real>::AddCost, MulCost = 4 * NumTraits<Real>::MulCost + 2 * NumTraits<Real>::AddCost }; - inline static Real epsilon() { return std::numeric_limits<Real>::epsilon(); } + inline static Real epsilon() { return NumTraits<Real>::epsilon(); } inline static Real dummy_precision() { return NumTraits<Real>::dummy_precision(); } }; -template<> struct NumTraits<long long int> - : ei_default_integral_numtraits<long long int> +template<typename Scalar, int Rows, int Cols, int Options, int MaxRows, int MaxCols> +struct NumTraits<Array<Scalar, Rows, Cols, Options, MaxRows, MaxCols> > { - typedef long long int Real; - typedef long double FloatingPoint; - typedef long long int Nested; + typedef Array<Scalar, Rows, Cols, Options, MaxRows, MaxCols> ArrayType; + typedef typename NumTraits<Scalar>::Real RealScalar; + typedef Array<RealScalar, Rows, Cols, Options, MaxRows, MaxCols> Real; + typedef typename NumTraits<Scalar>::NonInteger NonIntegerScalar; + typedef Array<NonIntegerScalar, Rows, Cols, Options, MaxRows, MaxCols> NonInteger; + typedef ArrayType & Nested; + enum { - IsComplex = 0, - HasFloatingPoint = 0, - ReadCost = 1, - AddCost = 1, - MulCost = 1 + IsComplex = NumTraits<Scalar>::IsComplex, + IsInteger = NumTraits<Scalar>::IsInteger, + IsSigned = NumTraits<Scalar>::IsSigned, + ReadCost = ArrayType::SizeAtCompileTime==Dynamic ? Dynamic : ArrayType::SizeAtCompileTime * NumTraits<Scalar>::ReadCost, + AddCost = ArrayType::SizeAtCompileTime==Dynamic ? Dynamic : ArrayType::SizeAtCompileTime * NumTraits<Scalar>::AddCost, + MulCost = ArrayType::SizeAtCompileTime==Dynamic ? Dynamic : ArrayType::SizeAtCompileTime * NumTraits<Scalar>::MulCost }; }; -template<> struct NumTraits<long double> - : ei_default_float_numtraits<long double> -{ - typedef long double Real; - typedef long double FloatingPoint; - typedef long double Nested; - enum { - IsComplex = 0, - HasFloatingPoint = 1, - ReadCost = 1, - AddCost = 1, - MulCost = 1 - }; - - static inline long double dummy_precision() { return NumTraits<double>::dummy_precision(); } -}; -template<> struct NumTraits<bool> - : ei_default_integral_numtraits<bool> -{ - typedef bool Real; - typedef float FloatingPoint; - typedef bool Nested; - enum { - IsComplex = 0, - HasFloatingPoint = 0, - ReadCost = 1, - AddCost = 1, - MulCost = 1 - }; -}; #endif // EIGEN_NUMTRAITS_H diff --git a/Eigen/src/Core/SelfCwiseBinaryOp.h b/Eigen/src/Core/SelfCwiseBinaryOp.h index 31d7edc31..f8f8a9f86 100644 --- a/Eigen/src/Core/SelfCwiseBinaryOp.h +++ b/Eigen/src/Core/SelfCwiseBinaryOp.h @@ -133,9 +133,11 @@ inline Derived& DenseBase<Derived>::operator*=(const Scalar& other) template<typename Derived> inline Derived& DenseBase<Derived>::operator/=(const Scalar& other) { - SelfCwiseBinaryOp<typename ei_meta_if<NumTraits<Scalar>::HasFloatingPoint,ei_scalar_product_op<Scalar>,ei_scalar_quotient_op<Scalar> >::ret, Derived> tmp(derived()); + SelfCwiseBinaryOp<typename ei_meta_if<NumTraits<Scalar>::IsInteger, + ei_scalar_quotient_op<Scalar>, + ei_scalar_product_op<Scalar> >::ret, Derived> tmp(derived()); typedef typename Derived::PlainObject PlainObject; - tmp = PlainObject::Constant(rows(),cols(), NumTraits<Scalar>::HasFloatingPoint ? Scalar(1)/other : other); + tmp = PlainObject::Constant(rows(),cols(), NumTraits<Scalar>::IsInteger ? other : Scalar(1)/other); return derived(); } diff --git a/Eigen/src/Core/util/StaticAssert.h b/Eigen/src/Core/util/StaticAssert.h index 31f7d0038..cf0db2901 100644 --- a/Eigen/src/Core/util/StaticAssert.h +++ b/Eigen/src/Core/util/StaticAssert.h @@ -65,7 +65,7 @@ YOU_CALLED_A_FIXED_SIZE_METHOD_ON_A_DYNAMIC_SIZE_MATRIX_OR_VECTOR, YOU_CALLED_A_DYNAMIC_SIZE_METHOD_ON_A_FIXED_SIZE_MATRIX_OR_VECTOR, UNALIGNED_LOAD_AND_STORE_OPERATIONS_UNIMPLEMENTED_ON_ALTIVEC, - NUMERIC_TYPE_MUST_BE_FLOATING_POINT, + THIS_FUNCTION_IS_NOT_FOR_INTEGER_NUMERIC_TYPES, NUMERIC_TYPE_MUST_BE_REAL, COEFFICIENT_WRITE_ACCESS_TO_SELFADJOINT_NOT_SUPPORTED, WRITING_TO_TRIANGULAR_PART_WITH_UNIT_DIAGONAL_IS_NOT_SUPPORTED, @@ -158,6 +158,9 @@ ) \ ) +#define EIGEN_STATIC_ASSERT_NON_INTEGER(TYPE) \ + EIGEN_STATIC_ASSERT(!NumTraits<TYPE>::IsInteger, THIS_FUNCTION_IS_NOT_FOR_INTEGER_NUMERIC_TYPES) + // static assertion failing if it is guaranteed at compile-time that the two matrix expression types have different sizes #define EIGEN_STATIC_ASSERT_SAME_MATRIX_SIZE(TYPE0,TYPE1) \ EIGEN_STATIC_ASSERT( \ diff --git a/Eigen/src/Geometry/AlignedBox.h b/Eigen/src/Geometry/AlignedBox.h index b5b40a82d..f3bee6f7d 100644 --- a/Eigen/src/Geometry/AlignedBox.h +++ b/Eigen/src/Geometry/AlignedBox.h @@ -46,7 +46,7 @@ EIGEN_MAKE_ALIGNED_OPERATOR_NEW_IF_VECTORIZABLE_FIXED_SIZE(_Scalar,_AmbientDim) typedef _Scalar Scalar; typedef NumTraits<Scalar> ScalarTraits; typedef typename ScalarTraits::Real RealScalar; - typedef typename ScalarTraits::FloatingPoint FloatingPoint; + typedef typename ScalarTraits::NonInteger NonInteger; typedef Matrix<Scalar,AmbientDimAtCompileTime,1> VectorType; /** Define constants to name the corners of a 1D, 2D or 3D axis aligned bounding box */ @@ -174,11 +174,10 @@ EIGEN_MAKE_ALIGNED_OPERATOR_NEW_IF_VECTORIZABLE_FIXED_SIZE(_Scalar,_AmbientDim) VectorType r; for(int d=0; d<dim(); ++d) { - if(ScalarTraits::HasFloatingPoint) + if(!ScalarTraits::IsInteger) { r[d] = m_min[d] + (m_max[d]-m_min[d]) - * (ei_random<Scalar>() + ei_random_amplitude<Scalar>()) - / (Scalar(2)*ei_random_amplitude<Scalar>() ); + * ei_random<Scalar>(Scalar(0), Scalar(1)); } else r[d] = ei_random(m_min[d], m_max[d]); @@ -260,15 +259,15 @@ EIGEN_MAKE_ALIGNED_OPERATOR_NEW_IF_VECTORIZABLE_FIXED_SIZE(_Scalar,_AmbientDim) * \sa squaredExteriorDistance() */ template<typename Derived> - inline FloatingPoint exteriorDistance(const MatrixBase<Derived>& p) const - { return ei_sqrt(FloatingPoint(squaredExteriorDistance(p))); } + inline NonInteger exteriorDistance(const MatrixBase<Derived>& p) const + { return ei_sqrt(NonInteger(squaredExteriorDistance(p))); } /** \returns the distance between the boxes \a b and \c *this, * and zero if the boxes intersect. * \sa squaredExteriorDistance() */ - inline FloatingPoint exteriorDistance(const AlignedBox& b) const - { return ei_sqrt(FloatingPoint(squaredExteriorDistance(b))); } + inline NonInteger exteriorDistance(const AlignedBox& b) const + { return ei_sqrt(NonInteger(squaredExteriorDistance(b))); } /** \returns \c *this with scalar type casted to \a NewScalarType * diff --git a/Eigen/src/LU/Inverse.h b/Eigen/src/LU/Inverse.h index 8e9012048..9e0c46094 100644 --- a/Eigen/src/LU/Inverse.h +++ b/Eigen/src/LU/Inverse.h @@ -1,7 +1,7 @@ // This file is part of Eigen, a lightweight C++ template library // for linear algebra. // -// Copyright (C) 2008-2009 Benoit Jacob <jacob.benoit.1@gmail.com> +// Copyright (C) 2008-2010 Benoit Jacob <jacob.benoit.1@gmail.com> // // Eigen is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -325,7 +325,7 @@ struct ei_inverse_impl : public ReturnByValue<ei_inverse_impl<MatrixType> > template<typename Derived> inline const ei_inverse_impl<Derived> MatrixBase<Derived>::inverse() const { - EIGEN_STATIC_ASSERT(NumTraits<Scalar>::HasFloatingPoint,NUMERIC_TYPE_MUST_BE_FLOATING_POINT) + EIGEN_STATIC_ASSERT(!NumTraits<Scalar>::IsInteger,THIS_FUNCTION_IS_NOT_FOR_INTEGER_NUMERIC_TYPES) ei_assert(rows() == cols()); return ei_inverse_impl<Derived>(derived()); } |