aboutsummaryrefslogtreecommitdiffhomepage
path: root/Eigen
diff options
context:
space:
mode:
authorGravatar Antonio Sanchez <cantonios@google.com>2021-03-10 21:27:35 -0800
committerGravatar Rasmus Munk Larsen <rmlarsen@google.com>2021-03-15 19:08:04 +0000
commit14b7ebea11808b2e44995e4a5cd668f1da4071c0 (patch)
tree2f21324ab3fbf24c763d646e0a51332a87d73215 /Eigen
parentc9d4367fa45dcc4d97289b70cba118c685c8e391 (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')
-rw-r--r--Eigen/src/Core/MathFunctions.h42
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