Provide a definition for numeric_limits static data members

This commit is contained in:
Rasmus Munk Larsen 2022-02-08 20:34:53 +00:00
parent b94bddcde0
commit 92d0026b7b
3 changed files with 140 additions and 29 deletions

View File

@ -125,11 +125,12 @@ struct bfloat16 : public bfloat16_impl::bfloat16_base {
return bfloat16_impl::bfloat16_to_float(*this);
}
};
} // namespace Eigen
namespace std {
template<>
struct numeric_limits<Eigen::bfloat16> {
// TODO(majnemer): Get rid of this once we can rely on C++17 inline variables do
// solve the ODR issue.
namespace bfloat16_impl {
template <typename = void>
struct numeric_limits_bfloat16_impl {
static EIGEN_CONSTEXPR const bool is_specialized = true;
static EIGEN_CONSTEXPR const bool is_signed = true;
static EIGEN_CONSTEXPR const bool is_integer = false;
@ -137,9 +138,9 @@ struct numeric_limits<Eigen::bfloat16> {
static EIGEN_CONSTEXPR const bool has_infinity = true;
static EIGEN_CONSTEXPR const bool has_quiet_NaN = true;
static EIGEN_CONSTEXPR const bool has_signaling_NaN = true;
static EIGEN_CONSTEXPR const float_denorm_style has_denorm = std::denorm_present;
static EIGEN_CONSTEXPR const std::float_denorm_style has_denorm = std::denorm_present;
static EIGEN_CONSTEXPR const bool has_denorm_loss = false;
static EIGEN_CONSTEXPR const std::float_round_style round_style = numeric_limits<float>::round_style;
static EIGEN_CONSTEXPR const std::float_round_style round_style = std::numeric_limits<float>::round_style;
static EIGEN_CONSTEXPR const bool is_iec559 = true;
// The C++ standard defines this as "true if the set of values representable
// by the type is finite." BFloat16 has finite precision.
@ -148,15 +149,15 @@ struct numeric_limits<Eigen::bfloat16> {
static EIGEN_CONSTEXPR const int digits = 8;
static EIGEN_CONSTEXPR const int digits10 = 2;
static EIGEN_CONSTEXPR const int max_digits10 = 4;
static EIGEN_CONSTEXPR const int radix = numeric_limits<float>::radix;
static EIGEN_CONSTEXPR const int min_exponent = numeric_limits<float>::min_exponent;
static EIGEN_CONSTEXPR const int min_exponent10 = numeric_limits<float>::min_exponent10;
static EIGEN_CONSTEXPR const int max_exponent = numeric_limits<float>::max_exponent;
static EIGEN_CONSTEXPR const int max_exponent10 = numeric_limits<float>::max_exponent10;
static EIGEN_CONSTEXPR const bool traps = numeric_limits<float>::traps;
static EIGEN_CONSTEXPR const int radix = std::numeric_limits<float>::radix;
static EIGEN_CONSTEXPR const int min_exponent = std::numeric_limits<float>::min_exponent;
static EIGEN_CONSTEXPR const int min_exponent10 = std::numeric_limits<float>::min_exponent10;
static EIGEN_CONSTEXPR const int max_exponent = std::numeric_limits<float>::max_exponent;
static EIGEN_CONSTEXPR const int max_exponent10 = std::numeric_limits<float>::max_exponent10;
static EIGEN_CONSTEXPR const bool traps = std::numeric_limits<float>::traps;
// IEEE754: "The implementer shall choose how tininess is detected, but shall
// detect tininess in the same way for all operations in radix two"
static EIGEN_CONSTEXPR const bool tinyness_before = numeric_limits<float>::tinyness_before;
static EIGEN_CONSTEXPR const bool tinyness_before = std::numeric_limits<float>::tinyness_before;
static EIGEN_CONSTEXPR Eigen::bfloat16 (min)() { return Eigen::bfloat16_impl::raw_uint16_to_bfloat16(0x0080); }
static EIGEN_CONSTEXPR Eigen::bfloat16 lowest() { return Eigen::bfloat16_impl::raw_uint16_to_bfloat16(0xff7f); }
@ -169,17 +170,69 @@ struct numeric_limits<Eigen::bfloat16> {
static EIGEN_CONSTEXPR Eigen::bfloat16 denorm_min() { return Eigen::bfloat16_impl::raw_uint16_to_bfloat16(0x0001); }
};
template<typename T>
EIGEN_CONSTEXPR const bool numeric_limits_bfloat16_impl<T>::is_specialized;
template<typename T>
EIGEN_CONSTEXPR const bool numeric_limits_bfloat16_impl<T>::is_signed;
template<typename T>
EIGEN_CONSTEXPR const bool numeric_limits_bfloat16_impl<T>::is_integer;
template<typename T>
EIGEN_CONSTEXPR const bool numeric_limits_bfloat16_impl<T>::is_exact;
template<typename T>
EIGEN_CONSTEXPR const bool numeric_limits_bfloat16_impl<T>::has_infinity;
template<typename T>
EIGEN_CONSTEXPR const bool numeric_limits_bfloat16_impl<T>::has_quiet_NaN;
template<typename T>
EIGEN_CONSTEXPR const bool numeric_limits_bfloat16_impl<T>::has_signaling_NaN;
template<typename T>
EIGEN_CONSTEXPR const std::float_denorm_style numeric_limits_bfloat16_impl<T>::has_denorm;
template<typename T>
EIGEN_CONSTEXPR const bool numeric_limits_bfloat16_impl<T>::has_denorm_loss;
template<typename T>
EIGEN_CONSTEXPR const std::float_round_style numeric_limits_bfloat16_impl<T>::round_style;
template<typename T>
EIGEN_CONSTEXPR const bool numeric_limits_bfloat16_impl<T>::is_iec559;
template<typename T>
EIGEN_CONSTEXPR const bool numeric_limits_bfloat16_impl<T>::is_bounded;
template<typename T>
EIGEN_CONSTEXPR const bool numeric_limits_bfloat16_impl<T>::is_modulo;
template<typename T>
EIGEN_CONSTEXPR const int numeric_limits_bfloat16_impl<T>::digits;
template<typename T>
EIGEN_CONSTEXPR const int numeric_limits_bfloat16_impl<T>::digits10;
template<typename T>
EIGEN_CONSTEXPR const int numeric_limits_bfloat16_impl<T>::max_digits10;
template<typename T>
EIGEN_CONSTEXPR const int numeric_limits_bfloat16_impl<T>::radix;
template<typename T>
EIGEN_CONSTEXPR const int numeric_limits_bfloat16_impl<T>::min_exponent;
template<typename T>
EIGEN_CONSTEXPR const int numeric_limits_bfloat16_impl<T>::min_exponent10;
template<typename T>
EIGEN_CONSTEXPR const int numeric_limits_bfloat16_impl<T>::max_exponent;
template<typename T>
EIGEN_CONSTEXPR const int numeric_limits_bfloat16_impl<T>::max_exponent10;
template<typename T>
EIGEN_CONSTEXPR const bool numeric_limits_bfloat16_impl<T>::traps;
template<typename T>
EIGEN_CONSTEXPR const bool numeric_limits_bfloat16_impl<T>::tinyness_before;
} // end namespace bfloat16_impl
} // end namespace Eigen
namespace std {
// If std::numeric_limits<T> is specialized, should also specialize
// std::numeric_limits<const T>, std::numeric_limits<volatile T>, and
// std::numeric_limits<const volatile T>
// https://stackoverflow.com/a/16519653/
template<>
struct numeric_limits<const Eigen::bfloat16> : numeric_limits<Eigen::bfloat16> {};
class numeric_limits<Eigen::bfloat16> : public Eigen::bfloat16_impl::numeric_limits_bfloat16_impl<> {};
template<>
struct numeric_limits<volatile Eigen::bfloat16> : numeric_limits<Eigen::bfloat16> {};
class numeric_limits<const Eigen::bfloat16> : public numeric_limits<Eigen::bfloat16> {};
template<>
struct numeric_limits<const volatile Eigen::bfloat16> : numeric_limits<Eigen::bfloat16> {};
} // namespace std
class numeric_limits<volatile Eigen::bfloat16> : public numeric_limits<Eigen::bfloat16> {};
template<>
class numeric_limits<const volatile Eigen::bfloat16> : public numeric_limits<Eigen::bfloat16> {};
} // end namespace std
namespace Eigen {

View File

@ -203,11 +203,11 @@ struct half : public half_impl::half_base {
#endif
};
} // end namespace Eigen
namespace std {
template<>
struct numeric_limits<Eigen::half> {
// TODO(majnemer): Get rid of this once we can rely on C++17 inline variables do
// solve the ODR issue.
namespace half_impl {
template <typename = void>
struct numeric_limits_half_impl {
static EIGEN_CONSTEXPR const bool is_specialized = true;
static EIGEN_CONSTEXPR const bool is_signed = true;
static EIGEN_CONSTEXPR const bool is_integer = false;
@ -215,7 +215,7 @@ struct numeric_limits<Eigen::half> {
static EIGEN_CONSTEXPR const bool has_infinity = true;
static EIGEN_CONSTEXPR const bool has_quiet_NaN = true;
static EIGEN_CONSTEXPR const bool has_signaling_NaN = true;
static EIGEN_CONSTEXPR const float_denorm_style has_denorm = denorm_present;
static EIGEN_CONSTEXPR const std::float_denorm_style has_denorm = std::denorm_present;
static EIGEN_CONSTEXPR const bool has_denorm_loss = false;
static EIGEN_CONSTEXPR const std::float_round_style round_style = std::round_to_nearest;
static EIGEN_CONSTEXPR const bool is_iec559 = true;
@ -226,12 +226,12 @@ struct numeric_limits<Eigen::half> {
static EIGEN_CONSTEXPR const int digits = 11;
static EIGEN_CONSTEXPR const int digits10 = 3; // according to http://half.sourceforge.net/structstd_1_1numeric__limits_3_01half__float_1_1half_01_4.html
static EIGEN_CONSTEXPR const int max_digits10 = 5; // according to http://half.sourceforge.net/structstd_1_1numeric__limits_3_01half__float_1_1half_01_4.html
static EIGEN_CONSTEXPR const int radix = numeric_limits<float>::radix;
static EIGEN_CONSTEXPR const int radix = std::numeric_limits<float>::radix;
static EIGEN_CONSTEXPR const int min_exponent = -13;
static EIGEN_CONSTEXPR const int min_exponent10 = -4;
static EIGEN_CONSTEXPR const int max_exponent = 16;
static EIGEN_CONSTEXPR const int max_exponent10 = 4;
static EIGEN_CONSTEXPR const bool traps = numeric_limits<float>::traps;
static EIGEN_CONSTEXPR const bool traps = std::numeric_limits<float>::traps;
// IEEE754: "The implementer shall choose how tininess is detected, but shall
// detect tininess in the same way for all operations in radix two"
static EIGEN_CONSTEXPR const bool tinyness_before = std::numeric_limits<float>::tinyness_before;
@ -247,17 +247,69 @@ struct numeric_limits<Eigen::half> {
static EIGEN_CONSTEXPR Eigen::half denorm_min() { return Eigen::half_impl::raw_uint16_to_half(0x0001); }
};
template<typename T>
EIGEN_CONSTEXPR const bool numeric_limits_half_impl<T>::is_specialized;
template<typename T>
EIGEN_CONSTEXPR const bool numeric_limits_half_impl<T>::is_signed;
template<typename T>
EIGEN_CONSTEXPR const bool numeric_limits_half_impl<T>::is_integer;
template<typename T>
EIGEN_CONSTEXPR const bool numeric_limits_half_impl<T>::is_exact;
template<typename T>
EIGEN_CONSTEXPR const bool numeric_limits_half_impl<T>::has_infinity;
template<typename T>
EIGEN_CONSTEXPR const bool numeric_limits_half_impl<T>::has_quiet_NaN;
template<typename T>
EIGEN_CONSTEXPR const bool numeric_limits_half_impl<T>::has_signaling_NaN;
template<typename T>
EIGEN_CONSTEXPR const std::float_denorm_style numeric_limits_half_impl<T>::has_denorm;
template<typename T>
EIGEN_CONSTEXPR const bool numeric_limits_half_impl<T>::has_denorm_loss;
template<typename T>
EIGEN_CONSTEXPR const std::float_round_style numeric_limits_half_impl<T>::round_style;
template<typename T>
EIGEN_CONSTEXPR const bool numeric_limits_half_impl<T>::is_iec559;
template<typename T>
EIGEN_CONSTEXPR const bool numeric_limits_half_impl<T>::is_bounded;
template<typename T>
EIGEN_CONSTEXPR const bool numeric_limits_half_impl<T>::is_modulo;
template<typename T>
EIGEN_CONSTEXPR const int numeric_limits_half_impl<T>::digits;
template<typename T>
EIGEN_CONSTEXPR const int numeric_limits_half_impl<T>::digits10;
template<typename T>
EIGEN_CONSTEXPR const int numeric_limits_half_impl<T>::max_digits10;
template<typename T>
EIGEN_CONSTEXPR const int numeric_limits_half_impl<T>::radix;
template<typename T>
EIGEN_CONSTEXPR const int numeric_limits_half_impl<T>::min_exponent;
template<typename T>
EIGEN_CONSTEXPR const int numeric_limits_half_impl<T>::min_exponent10;
template<typename T>
EIGEN_CONSTEXPR const int numeric_limits_half_impl<T>::max_exponent;
template<typename T>
EIGEN_CONSTEXPR const int numeric_limits_half_impl<T>::max_exponent10;
template<typename T>
EIGEN_CONSTEXPR const bool numeric_limits_half_impl<T>::traps;
template<typename T>
EIGEN_CONSTEXPR const bool numeric_limits_half_impl<T>::tinyness_before;
} // end namespace half_impl
} // end namespace Eigen
namespace std {
// If std::numeric_limits<T> is specialized, should also specialize
// std::numeric_limits<const T>, std::numeric_limits<volatile T>, and
// std::numeric_limits<const volatile T>
// https://stackoverflow.com/a/16519653/
template<>
struct numeric_limits<const Eigen::half> : numeric_limits<Eigen::half> {};
class numeric_limits<Eigen::half> : public Eigen::half_impl::numeric_limits_half_impl<> {};
template<>
struct numeric_limits<volatile Eigen::half> : numeric_limits<Eigen::half> {};
class numeric_limits<const Eigen::half> : public numeric_limits<Eigen::half> {};
template<>
struct numeric_limits<const volatile Eigen::half> : numeric_limits<Eigen::half> {};
} // end namespace std
class numeric_limits<volatile Eigen::half> : public numeric_limits<Eigen::half> {};
template<>
class numeric_limits<const volatile Eigen::half> : public numeric_limits<Eigen::half> {};
} // end namespace std
namespace Eigen {

View File

@ -157,6 +157,12 @@ void test_numtraits()
VERIFY( (std::numeric_limits<half>::denorm_min)() > half(0.f) );
VERIFY( (std::numeric_limits<half>::min)()/half(2) > half(0.f) );
VERIFY_IS_EQUAL( (std::numeric_limits<half>::denorm_min)()/half(2), half(0.f) );
// Test to see that we are able to link against the symbols for digits and
// digits10.
volatile const int& digits10 = std::numeric_limits<half>::digits10;
volatile const int& digits = std::numeric_limits<half>::digits;
VERIFY( (digits10) != (digits) );
}
void test_arithmetic()