diff options
author | Antonio Sanchez <cantonios@google.com> | 2021-03-10 21:27:35 -0800 |
---|---|---|
committer | Rasmus Munk Larsen <rmlarsen@google.com> | 2021-03-15 19:08:04 +0000 |
commit | 14b7ebea11808b2e44995e4a5cd668f1da4071c0 (patch) | |
tree | 2f21324ab3fbf24c763d646e0a51332a87d73215 /Eigen/src/Core/MathFunctions.h | |
parent | c9d4367fa45dcc4d97289b70cba118c685c8e391 (diff) |
Fix numext::round pre c++11 for large inputs.
This is to resolve an issue for large inputs when +0.5 can
actually lead to +1 if the input doesn't have enough precision
to resolve the addition - leading to an off-by-one error.
See discussion on 9a663973.
Diffstat (limited to 'Eigen/src/Core/MathFunctions.h')
-rw-r--r-- | Eigen/src/Core/MathFunctions.h | 42 |
1 files changed, 23 insertions, 19 deletions
diff --git a/Eigen/src/Core/MathFunctions.h b/Eigen/src/Core/MathFunctions.h index e29733c13..7c67ffdf7 100644 --- a/Eigen/src/Core/MathFunctions.h +++ b/Eigen/src/Core/MathFunctions.h @@ -476,31 +476,35 @@ inline NewType cast(const OldType& x) * Implementation of round * ****************************************************************************/ +template<typename Scalar> +struct round_impl +{ + EIGEN_DEVICE_FUNC + static inline Scalar run(const Scalar& x) + { + EIGEN_STATIC_ASSERT((!NumTraits<Scalar>::IsComplex), NUMERIC_TYPE_MUST_BE_REAL) #if EIGEN_HAS_CXX11_MATH - template<typename Scalar> - struct round_impl { - EIGEN_DEVICE_FUNC - static inline Scalar run(const Scalar& x) - { - EIGEN_STATIC_ASSERT((!NumTraits<Scalar>::IsComplex), NUMERIC_TYPE_MUST_BE_REAL) - EIGEN_USING_STD(round); + EIGEN_USING_STD(round); + return Scalar(round(x)); +#elif EIGEN_HAS_C99_MATH + if (is_same<Scalar, float>::value) { + return Scalar(::roundf(x)); + } else { return Scalar(round(x)); } - }; #else - template<typename Scalar> - struct round_impl - { - EIGEN_DEVICE_FUNC - static inline Scalar run(const Scalar& x) - { - EIGEN_STATIC_ASSERT((!NumTraits<Scalar>::IsComplex), NUMERIC_TYPE_MUST_BE_REAL) - EIGEN_USING_STD(floor); - EIGEN_USING_STD(ceil); - return (x > Scalar(0)) ? floor(x + Scalar(0.5)) : ceil(x - Scalar(0.5)); + EIGEN_USING_STD(floor); + EIGEN_USING_STD(ceil); + // If not enough precision to resolve a decimal at all, return the input. + // Otherwise, adding 0.5 can trigger an increment by 1. + const Scalar limit = Scalar(1ull << (NumTraits<Scalar>::digits() - 1)); + if (x >= limit || x <= -limit) { + return x; } - }; + return (x > Scalar(0)) ? Scalar(floor(x + Scalar(0.5))) : Scalar(ceil(x - Scalar(0.5))); #endif + } +}; template<typename Scalar> struct round_retval |