Fixes #2703 by adding max_digits10 function

This commit is contained in:
Yingnan Wu 2023-07-26 16:02:52 +00:00 committed by Antonio Sánchez
parent 9995c3da6f
commit ba1cb6e45e
5 changed files with 81 additions and 34 deletions

View File

@ -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<typename Scalar>
struct significant_decimals_impl
{
static inline int run()
{
return NumTraits<Scalar>::digits10();
return NumTraits<Scalar>::max_digits10();
}
};

View File

@ -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<T>::is_specialized,
bool is_integer = NumTraits<T>::IsInteger>
struct default_digits10_impl
{
EIGEN_DEVICE_FUNC EIGEN_CONSTEXPR
static int run() { return std::numeric_limits<T>::digits10; }
};
template<typename T>
struct default_digits10_impl<T,false,false> // Floating point
{
EIGEN_DEVICE_FUNC EIGEN_CONSTEXPR
static int run() {
using std::log10;
using std::ceil;
typedef typename NumTraits<T>::Real Real;
return int(ceil(-log10(NumTraits<Real>::epsilon())));
}
};
template<typename T>
struct default_digits10_impl<T,false,true> // 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<T,false,true> // 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<T>::is_specialized,
bool is_integer = NumTraits<T>::IsInteger>
struct default_digits10_impl
{
EIGEN_DEVICE_FUNC EIGEN_CONSTEXPR
static int run() { return std::numeric_limits<T>::digits10; }
};
template<typename T>
struct default_digits10_impl<T,false,false> // Floating point
{
EIGEN_DEVICE_FUNC EIGEN_CONSTEXPR
static int run() {
using std::log10;
using std::floor;
typedef typename NumTraits<T>::Real Real;
return int(floor((internal::default_digits_impl<Real>::run()-1)*log10(2)));
}
};
template<typename T>
struct default_digits10_impl<T,false,true> // 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<T>::is_specialized,
bool is_integer = NumTraits<T>::IsInteger>
struct default_max_digits10_impl
{
EIGEN_DEVICE_FUNC EIGEN_CONSTEXPR
static int run() { return std::numeric_limits<T>::max_digits10; }
};
template<typename T>
struct default_max_digits10_impl<T,false,false> // Floating point
{
EIGEN_DEVICE_FUNC EIGEN_CONSTEXPR
static int run() {
using std::log10;
using std::ceil;
typedef typename NumTraits<T>::Real Real;
return int(ceil(internal::default_digits_impl<Real>::run()*log10(2)+1));
}
};
template<typename T>
struct default_max_digits10_impl<T,false,true> // 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 <a href="http://en.cppreference.com/w/cpp/types/numeric_limits/digits10">std::numeric_limits<T>::digits10</a>
* 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 <a href="http://en.cppreference.com/w/cpp/types/numeric_limits/max_digits10">std::numeric_limits<T>::max_digits10</a>
* 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
* <a href="http://en.cppreference.com/w/cpp/types/numeric_limits/min_exponent">std::numeric_limits<T>::min_exponent</a>/
@ -180,6 +212,12 @@ template<typename T> struct GenericNumTraits
return internal::default_digits10_impl<T>::run();
}
EIGEN_DEVICE_FUNC EIGEN_CONSTEXPR
static inline int max_digits10()
{
return internal::default_max_digits10_impl<T>::run();
}
EIGEN_DEVICE_FUNC EIGEN_CONSTEXPR
static inline int digits()
{
@ -282,6 +320,8 @@ template<typename Real_> struct NumTraits<std::complex<Real_> >
static inline Real dummy_precision() { return NumTraits<Real>::dummy_precision(); }
EIGEN_DEVICE_FUNC EIGEN_CONSTEXPR
static inline int digits10() { return NumTraits<Real>::digits10(); }
EIGEN_DEVICE_FUNC EIGEN_CONSTEXPR
static inline int max_digits10() { return NumTraits<Real>::max_digits10(); }
};
template<typename Scalar, int Rows, int Cols, int Options, int MaxRows, int MaxCols>
@ -312,6 +352,8 @@ struct NumTraits<Array<Scalar, Rows, Cols, Options, MaxRows, MaxCols> >
EIGEN_CONSTEXPR
static inline int digits10() { return NumTraits<Scalar>::digits10(); }
EIGEN_CONSTEXPR
static inline int max_digits10() { return NumTraits<Scalar>::max_digits10(); }
};
template<> struct NumTraits<std::string>
@ -326,8 +368,10 @@ template<> struct NumTraits<std::string>
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();

View File

@ -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,

View File

@ -156,6 +156,7 @@ EIGEN_DECLARE_TEST(boostmultiprec)
std::cout << "NumTraits<Real>::lowest() = " << NumTraits<Real>::lowest() << std::endl;
std::cout << "NumTraits<Real>::highest() = " << NumTraits<Real>::highest() << std::endl;
std::cout << "NumTraits<Real>::digits10() = " << NumTraits<Real>::digits10() << std::endl;
std::cout << "NumTraits<Real>::max_digits10() = " << NumTraits<Real>::max_digits10() << std::endl;
// check stream output
{

View File

@ -20,6 +20,7 @@ EIGEN_DECLARE_TEST(mpreal_support)
std::cerr << "highest = " << NumTraits<mpreal>::highest() << "\n";
std::cerr << "lowest = " << NumTraits<mpreal>::lowest() << "\n";
std::cerr << "digits10 = " << NumTraits<mpreal>::digits10() << "\n";
std::cerr << "max_digits10 = " << NumTraits<mpreal>::max_digits10() << "\n";
for(int i = 0; i < g_repeat; i++) {
int s = Eigen::internal::random<int>(1,100);