From ca0c699d2374cf31d29eb36ae5ff2a9ef5e6dd34 Mon Sep 17 00:00:00 2001 From: danieltowner Date: Fri, 9 Oct 2026 18:30:44 +0100 Subject: [PATCH] Fixed behaviour of min/max (issue #43) The elementwise min/max previously used don't match the std::min/std::max functions (they introduce extra NaN handling), so revert to a variant based on select instead. --- include/xvec/generic/generic_impl.hpp | 25 ++++++++----------------- 1 file changed, 8 insertions(+), 17 deletions(-) diff --git a/include/xvec/generic/generic_impl.hpp b/include/xvec/generic/generic_impl.hpp index c1465f7..4e8d09f 100644 --- a/include/xvec/generic/generic_impl.hpp +++ b/include/xvec/generic/generic_impl.hpp @@ -1027,31 +1027,22 @@ constexpr basic_vec<_Tp, _Abi> abs(generic_tag, const basic_vec<_Tp, _Abi>& v) } ///@} -/// @brief Compute the minimum or maximum of each element pair. +/// @brief Compute the minimum or maximum of each element pair. The behaviour of +/// the select exactly matches the behaviour of the underlying std::min and +/// std::max functions. Note that elementwise_min/max, elementwise_minimum/maximum +/// and elementwise_minnum/maxnum all have different behaviours with regard to NaN +/// values (e.g., introducing extra operations to handle NaNs in specified ways), +/// but none of them match the behaviour of std::min/std::max. /// @tparam _Vp The type of vec to operate on /// @param lhs The left-hand value /// @param rhs The right-hand value /// @return The elementwise minimum or maximum vec ///@{ template -constexpr _Vp minimum(generic_tag, const _Vp& lhs, const _Vp& rhs) -{ - #if __has_builtin(__builtin_elementwise_min) - return __builtin_elementwise_min(lhs.to_builtin(), rhs.to_builtin()); - #else - return select(lhs < rhs, lhs, rhs); - #endif -} +constexpr _Vp minimum(generic_tag, const _Vp& lhs, const _Vp& rhs) { return select(rhs < lhs, rhs, lhs); } template -constexpr _Vp maximum(generic_tag, const _Vp& lhs, const _Vp& rhs) -{ - #if __has_builtin(__builtin_elementwise_max) - return __builtin_elementwise_max(lhs.to_builtin(), rhs.to_builtin()); - #else - return select(lhs < rhs, rhs, lhs); - #endif -} +constexpr _Vp maximum(generic_tag, const _Vp& lhs, const _Vp& rhs) { return select(lhs < rhs, rhs, lhs); } ///@} /// @brief Saturated cast to a new type. Every element is converted to the new type, or