From ba1cb6e45eda044acbf794738a2109f2bddf0b6b Mon Sep 17 00:00:00 2001 From: Yingnan Wu Date: Wed, 26 Jul 2023 16:02:52 +0000 Subject: [PATCH] Fixes #2703 by adding max_digits10 function --- Eigen/src/Core/IO.h | 4 +- Eigen/src/Core/NumTraits.h | 108 ++++++++++++++++++-------- doc/CustomizingEigen_CustomScalar.dox | 1 + test/boostmultiprec.cpp | 1 + unsupported/test/mpreal_support.cpp | 1 + 5 files changed, 81 insertions(+), 34 deletions(-) diff --git a/Eigen/src/Core/IO.h b/Eigen/src/Core/IO.h index 053905fe2..69937292b 100644 --- a/Eigen/src/Core/IO.h +++ b/Eigen/src/Core/IO.h @@ -117,13 +117,13 @@ namespace internal { // NOTE: This helper is kept for backward compatibility with previous code specializing // this internal::significant_decimals_impl structure. In the future we should directly -// call digits10() which has been introduced in July 2016 in 3.3. +// call max_digits10(). template struct significant_decimals_impl { static inline int run() { - return NumTraits::digits10(); + return NumTraits::max_digits10(); } }; diff --git a/Eigen/src/Core/NumTraits.h b/Eigen/src/Core/NumTraits.h index ff33aa6fb..f5275d804 100644 --- a/Eigen/src/Core/NumTraits.h +++ b/Eigen/src/Core/NumTraits.h @@ -16,37 +16,6 @@ namespace Eigen { namespace internal { -// default implementation of digits10(), based on numeric_limits if specialized, -// 0 for integer types, and log10(epsilon()) otherwise. -template< typename T, - bool use_numeric_limits = std::numeric_limits::is_specialized, - bool is_integer = NumTraits::IsInteger> -struct default_digits10_impl -{ - EIGEN_DEVICE_FUNC EIGEN_CONSTEXPR - static int run() { return std::numeric_limits::digits10; } -}; - -template -struct default_digits10_impl // Floating point -{ - EIGEN_DEVICE_FUNC EIGEN_CONSTEXPR - static int run() { - using std::log10; - using std::ceil; - typedef typename NumTraits::Real Real; - return int(ceil(-log10(NumTraits::epsilon()))); - } -}; - -template -struct default_digits10_impl // Integer -{ - EIGEN_DEVICE_FUNC EIGEN_CONSTEXPR - static int run() { return 0; } -}; - - // default implementation of digits(), based on numeric_limits if specialized, // 0 for integer types, and log2(epsilon()) otherwise. template< typename T, @@ -77,6 +46,66 @@ struct default_digits_impl // Integer static int run() { return 0; } }; +// default implementation of digits10(), based on numeric_limits if specialized, +// 0 for integer types, and floor((digits()-1)*log10(2)) otherwise. +template< typename T, + bool use_numeric_limits = std::numeric_limits::is_specialized, + bool is_integer = NumTraits::IsInteger> +struct default_digits10_impl +{ + EIGEN_DEVICE_FUNC EIGEN_CONSTEXPR + static int run() { return std::numeric_limits::digits10; } +}; + +template +struct default_digits10_impl // Floating point +{ + EIGEN_DEVICE_FUNC EIGEN_CONSTEXPR + static int run() { + using std::log10; + using std::floor; + typedef typename NumTraits::Real Real; + return int(floor((internal::default_digits_impl::run()-1)*log10(2))); + } +}; + +template +struct default_digits10_impl // Integer +{ + EIGEN_DEVICE_FUNC EIGEN_CONSTEXPR + static int run() { return 0; } +}; + +// default implementation of max_digits10(), based on numeric_limits if specialized, +// 0 for integer types, and log10(2) * digits() + 1 otherwise. +template< typename T, + bool use_numeric_limits = std::numeric_limits::is_specialized, + bool is_integer = NumTraits::IsInteger> +struct default_max_digits10_impl +{ + EIGEN_DEVICE_FUNC EIGEN_CONSTEXPR + static int run() { return std::numeric_limits::max_digits10; } +}; + +template +struct default_max_digits10_impl // Floating point +{ + EIGEN_DEVICE_FUNC EIGEN_CONSTEXPR + static int run() { + using std::log10; + using std::ceil; + typedef typename NumTraits::Real Real; + return int(ceil(internal::default_digits_impl::run()*log10(2)+1)); + } +}; + +template +struct default_max_digits10_impl // Integer +{ + EIGEN_DEVICE_FUNC EIGEN_CONSTEXPR + static int run() { return 0; } +}; + } // end namespace internal namespace numext { @@ -143,6 +172,9 @@ EIGEN_STRONG_INLINE EIGEN_DEVICE_FUNC Tgt bit_cast(const Src& src) { * \li digits10() function returning the number of decimal digits that can be represented without change. This is * the analogue of std::numeric_limits::digits10 * which is used as the default implementation if specialized. + * \li max_digits10() function returning the number of decimal digits required to uniquely represent all distinct values of the type. This is + * the analogue of std::numeric_limits::max_digits10 + * which is used as the default implementation if specialized. * \li min_exponent() and max_exponent() functions returning the highest and lowest possible values, respectively, * such that the radix raised to the power exponent-1 is a normalized floating-point number. These are equivalent to * std::numeric_limits::min_exponent/ @@ -180,6 +212,12 @@ template struct GenericNumTraits return internal::default_digits10_impl::run(); } + EIGEN_DEVICE_FUNC EIGEN_CONSTEXPR + static inline int max_digits10() + { + return internal::default_max_digits10_impl::run(); + } + EIGEN_DEVICE_FUNC EIGEN_CONSTEXPR static inline int digits() { @@ -282,6 +320,8 @@ template struct NumTraits > static inline Real dummy_precision() { return NumTraits::dummy_precision(); } EIGEN_DEVICE_FUNC EIGEN_CONSTEXPR static inline int digits10() { return NumTraits::digits10(); } + EIGEN_DEVICE_FUNC EIGEN_CONSTEXPR + static inline int max_digits10() { return NumTraits::max_digits10(); } }; template @@ -312,6 +352,8 @@ struct NumTraits > EIGEN_CONSTEXPR static inline int digits10() { return NumTraits::digits10(); } + EIGEN_CONSTEXPR + static inline int max_digits10() { return NumTraits::max_digits10(); } }; template<> struct NumTraits @@ -326,8 +368,10 @@ template<> struct NumTraits EIGEN_CONSTEXPR static inline int digits10() { return 0; } + EIGEN_CONSTEXPR + static inline int max_digits10() { return 0; } -private: + private: static inline std::string epsilon(); static inline std::string dummy_precision(); static inline std::string lowest(); diff --git a/doc/CustomizingEigen_CustomScalar.dox b/doc/CustomizingEigen_CustomScalar.dox index 24e5f563b..672cfc3de 100644 --- a/doc/CustomizingEigen_CustomScalar.dox +++ b/doc/CustomizingEigen_CustomScalar.dox @@ -76,6 +76,7 @@ namespace Eigen { static inline Real epsilon() { return 0; } static inline Real dummy_precision() { return 0; } static inline int digits10() { return 0; } + static inline int max_digits10() { return 0; } enum { IsInteger = 0, diff --git a/test/boostmultiprec.cpp b/test/boostmultiprec.cpp index e2fc9a811..5759888c9 100644 --- a/test/boostmultiprec.cpp +++ b/test/boostmultiprec.cpp @@ -156,6 +156,7 @@ EIGEN_DECLARE_TEST(boostmultiprec) std::cout << "NumTraits::lowest() = " << NumTraits::lowest() << std::endl; std::cout << "NumTraits::highest() = " << NumTraits::highest() << std::endl; std::cout << "NumTraits::digits10() = " << NumTraits::digits10() << std::endl; + std::cout << "NumTraits::max_digits10() = " << NumTraits::max_digits10() << std::endl; // check stream output { diff --git a/unsupported/test/mpreal_support.cpp b/unsupported/test/mpreal_support.cpp index 10beb0714..7256dc0e5 100644 --- a/unsupported/test/mpreal_support.cpp +++ b/unsupported/test/mpreal_support.cpp @@ -20,6 +20,7 @@ EIGEN_DECLARE_TEST(mpreal_support) std::cerr << "highest = " << NumTraits::highest() << "\n"; std::cerr << "lowest = " << NumTraits::lowest() << "\n"; std::cerr << "digits10 = " << NumTraits::digits10() << "\n"; + std::cerr << "max_digits10 = " << NumTraits::max_digits10() << "\n"; for(int i = 0; i < g_repeat; i++) { int s = Eigen::internal::random(1,100);