diff --git a/Eigen/src/Core/arch/Default/BFloat16.h b/Eigen/src/Core/arch/Default/BFloat16.h index fb99d8680..c444b8a5d 100644 --- a/Eigen/src/Core/arch/Default/BFloat16.h +++ b/Eigen/src/Core/arch/Default/BFloat16.h @@ -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 { +// TODO(majnemer): Get rid of this once we can rely on C++17 inline variables do +// solve the ODR issue. +namespace bfloat16_impl { +template +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 { 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::round_style; + static EIGEN_CONSTEXPR const std::float_round_style round_style = std::numeric_limits::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 { 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::radix; - static EIGEN_CONSTEXPR const int min_exponent = numeric_limits::min_exponent; - static EIGEN_CONSTEXPR const int min_exponent10 = numeric_limits::min_exponent10; - static EIGEN_CONSTEXPR const int max_exponent = numeric_limits::max_exponent; - static EIGEN_CONSTEXPR const int max_exponent10 = numeric_limits::max_exponent10; - static EIGEN_CONSTEXPR const bool traps = numeric_limits::traps; + static EIGEN_CONSTEXPR const int radix = std::numeric_limits::radix; + static EIGEN_CONSTEXPR const int min_exponent = std::numeric_limits::min_exponent; + static EIGEN_CONSTEXPR const int min_exponent10 = std::numeric_limits::min_exponent10; + static EIGEN_CONSTEXPR const int max_exponent = std::numeric_limits::max_exponent; + static EIGEN_CONSTEXPR const int max_exponent10 = std::numeric_limits::max_exponent10; + static EIGEN_CONSTEXPR const bool traps = std::numeric_limits::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::tinyness_before; + static EIGEN_CONSTEXPR const bool tinyness_before = std::numeric_limits::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 { static EIGEN_CONSTEXPR Eigen::bfloat16 denorm_min() { return Eigen::bfloat16_impl::raw_uint16_to_bfloat16(0x0001); } }; +template +EIGEN_CONSTEXPR const bool numeric_limits_bfloat16_impl::is_specialized; +template +EIGEN_CONSTEXPR const bool numeric_limits_bfloat16_impl::is_signed; +template +EIGEN_CONSTEXPR const bool numeric_limits_bfloat16_impl::is_integer; +template +EIGEN_CONSTEXPR const bool numeric_limits_bfloat16_impl::is_exact; +template +EIGEN_CONSTEXPR const bool numeric_limits_bfloat16_impl::has_infinity; +template +EIGEN_CONSTEXPR const bool numeric_limits_bfloat16_impl::has_quiet_NaN; +template +EIGEN_CONSTEXPR const bool numeric_limits_bfloat16_impl::has_signaling_NaN; +template +EIGEN_CONSTEXPR const std::float_denorm_style numeric_limits_bfloat16_impl::has_denorm; +template +EIGEN_CONSTEXPR const bool numeric_limits_bfloat16_impl::has_denorm_loss; +template +EIGEN_CONSTEXPR const std::float_round_style numeric_limits_bfloat16_impl::round_style; +template +EIGEN_CONSTEXPR const bool numeric_limits_bfloat16_impl::is_iec559; +template +EIGEN_CONSTEXPR const bool numeric_limits_bfloat16_impl::is_bounded; +template +EIGEN_CONSTEXPR const bool numeric_limits_bfloat16_impl::is_modulo; +template +EIGEN_CONSTEXPR const int numeric_limits_bfloat16_impl::digits; +template +EIGEN_CONSTEXPR const int numeric_limits_bfloat16_impl::digits10; +template +EIGEN_CONSTEXPR const int numeric_limits_bfloat16_impl::max_digits10; +template +EIGEN_CONSTEXPR const int numeric_limits_bfloat16_impl::radix; +template +EIGEN_CONSTEXPR const int numeric_limits_bfloat16_impl::min_exponent; +template +EIGEN_CONSTEXPR const int numeric_limits_bfloat16_impl::min_exponent10; +template +EIGEN_CONSTEXPR const int numeric_limits_bfloat16_impl::max_exponent; +template +EIGEN_CONSTEXPR const int numeric_limits_bfloat16_impl::max_exponent10; +template +EIGEN_CONSTEXPR const bool numeric_limits_bfloat16_impl::traps; +template +EIGEN_CONSTEXPR const bool numeric_limits_bfloat16_impl::tinyness_before; +} // end namespace bfloat16_impl +} // end namespace Eigen + +namespace std { // If std::numeric_limits is specialized, should also specialize // std::numeric_limits, std::numeric_limits, and // std::numeric_limits // https://stackoverflow.com/a/16519653/ template<> -struct numeric_limits : numeric_limits {}; +class numeric_limits : public Eigen::bfloat16_impl::numeric_limits_bfloat16_impl<> {}; template<> -struct numeric_limits : numeric_limits {}; +class numeric_limits : public numeric_limits {}; template<> -struct numeric_limits : numeric_limits {}; -} // namespace std +class numeric_limits : public numeric_limits {}; +template<> +class numeric_limits : public numeric_limits {}; +} // end namespace std namespace Eigen { diff --git a/Eigen/src/Core/arch/Default/Half.h b/Eigen/src/Core/arch/Default/Half.h index 876045e58..402b8d463 100644 --- a/Eigen/src/Core/arch/Default/Half.h +++ b/Eigen/src/Core/arch/Default/Half.h @@ -203,11 +203,11 @@ struct half : public half_impl::half_base { #endif }; -} // end namespace Eigen - -namespace std { -template<> -struct numeric_limits { +// TODO(majnemer): Get rid of this once we can rely on C++17 inline variables do +// solve the ODR issue. +namespace half_impl { +template +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 { 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 { 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::radix; + static EIGEN_CONSTEXPR const int radix = std::numeric_limits::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::traps; + static EIGEN_CONSTEXPR const bool traps = std::numeric_limits::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::tinyness_before; @@ -247,17 +247,69 @@ struct numeric_limits { static EIGEN_CONSTEXPR Eigen::half denorm_min() { return Eigen::half_impl::raw_uint16_to_half(0x0001); } }; +template +EIGEN_CONSTEXPR const bool numeric_limits_half_impl::is_specialized; +template +EIGEN_CONSTEXPR const bool numeric_limits_half_impl::is_signed; +template +EIGEN_CONSTEXPR const bool numeric_limits_half_impl::is_integer; +template +EIGEN_CONSTEXPR const bool numeric_limits_half_impl::is_exact; +template +EIGEN_CONSTEXPR const bool numeric_limits_half_impl::has_infinity; +template +EIGEN_CONSTEXPR const bool numeric_limits_half_impl::has_quiet_NaN; +template +EIGEN_CONSTEXPR const bool numeric_limits_half_impl::has_signaling_NaN; +template +EIGEN_CONSTEXPR const std::float_denorm_style numeric_limits_half_impl::has_denorm; +template +EIGEN_CONSTEXPR const bool numeric_limits_half_impl::has_denorm_loss; +template +EIGEN_CONSTEXPR const std::float_round_style numeric_limits_half_impl::round_style; +template +EIGEN_CONSTEXPR const bool numeric_limits_half_impl::is_iec559; +template +EIGEN_CONSTEXPR const bool numeric_limits_half_impl::is_bounded; +template +EIGEN_CONSTEXPR const bool numeric_limits_half_impl::is_modulo; +template +EIGEN_CONSTEXPR const int numeric_limits_half_impl::digits; +template +EIGEN_CONSTEXPR const int numeric_limits_half_impl::digits10; +template +EIGEN_CONSTEXPR const int numeric_limits_half_impl::max_digits10; +template +EIGEN_CONSTEXPR const int numeric_limits_half_impl::radix; +template +EIGEN_CONSTEXPR const int numeric_limits_half_impl::min_exponent; +template +EIGEN_CONSTEXPR const int numeric_limits_half_impl::min_exponent10; +template +EIGEN_CONSTEXPR const int numeric_limits_half_impl::max_exponent; +template +EIGEN_CONSTEXPR const int numeric_limits_half_impl::max_exponent10; +template +EIGEN_CONSTEXPR const bool numeric_limits_half_impl::traps; +template +EIGEN_CONSTEXPR const bool numeric_limits_half_impl::tinyness_before; +} // end namespace half_impl +} // end namespace Eigen + +namespace std { // If std::numeric_limits is specialized, should also specialize // std::numeric_limits, std::numeric_limits, and // std::numeric_limits // https://stackoverflow.com/a/16519653/ template<> -struct numeric_limits : numeric_limits {}; +class numeric_limits : public Eigen::half_impl::numeric_limits_half_impl<> {}; template<> -struct numeric_limits : numeric_limits {}; +class numeric_limits : public numeric_limits {}; template<> -struct numeric_limits : numeric_limits {}; -} // end namespace std +class numeric_limits : public numeric_limits {}; +template<> +class numeric_limits : public numeric_limits {}; +} // end namespace std namespace Eigen { diff --git a/test/half_float.cpp b/test/half_float.cpp index 729de1bc7..f2c1ac8b6 100644 --- a/test/half_float.cpp +++ b/test/half_float.cpp @@ -157,6 +157,12 @@ void test_numtraits() VERIFY( (std::numeric_limits::denorm_min)() > half(0.f) ); VERIFY( (std::numeric_limits::min)()/half(2) > half(0.f) ); VERIFY_IS_EQUAL( (std::numeric_limits::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::digits10; + volatile const int& digits = std::numeric_limits::digits; + VERIFY( (digits10) != (digits) ); } void test_arithmetic()