29 Numerics library [numerics]

29.10 Data-parallel types [simd]

29.10.1 General [simd.general]

Subclause [simd] defines data-parallel types and operations on these types.
[Note 1: 
The intent is to support acceleration through data-parallel execution resources where available, such as SIMD registers and instructions or execution units driven by a common instruction decoder.
SIMD stands for “Single Instruction Stream – Multiple Data Stream”; it is defined in Flynn 1966[bib].
— end note]
The set of vectorizable types comprises all standard integer types, character types, and the types float and double ([basic.fundamental]).
In addition, std​::​float16_t, std​::​float32_t, and std​::​float64_t are vectorizable types if defined ([basic.extended.fp]).
The term data-parallel type refers to all enabled specializations of the basic_simd and basic_simd_mask class templates.
A data-parallel object is an object of data-parallel type.
Each specialization of basic_simd or basic_simd_mask is either enabled or disabled, as described in [simd.overview] and [simd.mask.overview].
A data-parallel type consists of one or more elements of an underlying vectorizable type, called the element type.
The number of elements is a constant for each data-parallel type and called the width of that type.
The elements in a data-parallel type are indexed from 0 to .
An element-wise operation applies a specified operation to the elements of one or more data-parallel objects.
Each such application is unsequenced with respect to the others.
A unary element-wise operation is an element-wise operation that applies a unary operation to each element of a data-parallel object.
A binary element-wise operation is an element-wise operation that applies a binary operation to corresponding elements of two data-parallel objects.
Given a basic_simd_mask<Bytes, Abi> object mask, the selected indices signify the integers i in the range [0, mask.size()) for which mask[i] is true.
Given a data-parallel object data, the selected elements signify the elements data[i] for all selected indices i.
The conversion from an arithmetic type U to a vectorizable type T is value-preserving if all possible values of U can be represented with type T.

29.10.2 Exposition-only types, variables, and concepts [simd.expos]

using simd-size-type = see below; // exposition only template<size_t Bytes> using integer-from = see below; // exposition only template<class T, class Abi> constexpr simd-size-type simd-size-v = see below; // exposition only template<class T> constexpr size_t mask-element-size = see below; // exposition only template<class T> concept constexpr-wrapper-like = // exposition only convertible_to<T, decltype(T::value)> && equality_comparable_with<T, decltype(T::value)> && bool_constant<T() == T::value>::value && bool_constant<static_cast<decltype(T::value)>(T()) == T::value>::value; template<class T> using deduced-simd-t = see below; // exposition only template<class V, class T> using make-compatible-simd-t = see below; // exposition only template<class V> concept simd-floating-point = // exposition only same_as<V, basic_simd<typename V::value_type, typename V::abi_type>> && is_default_constructible_v<V> && floating_point<typename V::value_type>; template<class... Ts> concept math-floating-point = // exposition only (simd-floating-point<deduced-simd-t<Ts>> || ...); template<class... Ts> requires math-floating-point<Ts...> using math-common-simd-t = see below; // exposition only template<class BinaryOperation, class T> concept reduction-binary-operation = see below; // exposition only // [simd.expos.abi], simd ABI tags template<class T> using native-abi = see below; // exposition only template<class T, simd-size-type N> using deduce-abi-t = see below; // exposition only // [simd.flags], Load and store flags struct convert-flag; // exposition only struct aligned-flag; // exposition only template<size_t N> struct overaligned-flag; // exposition only

29.10.2.1 Exposition-only helpers [simd.expos.defn]

using simd-size-type = see below;
simd-size-type is an alias for a signed integer type.
template<size_t Bytes> using integer-from = see below;
integer-from<Bytes> is an alias for a signed integer type T such that sizeof(T) equals Bytes.
template<class T, class Abi> constexpr simd-size-type simd-size-v = see below;
simd-size-v<T, Abi> denotes the width of basic_simd<T, Abi> if the specialization basic_simd<T, Abi> is enabled, or 0 otherwise.
template<class T> constexpr size_t mask-element-size = see below;
mask-element-size<basic_simd_mask<Bytes, Abi>> has the value Bytes.
template<class T> using deduced-simd-t = see below;
Let x denote an lvalue of type const T.
deduced-simd-t<T> is an alias for
  • decltype(x + x), if the type of x + x is an enabled specialization of basic_simd; otherwise
  • void.
template<class V, class T> using make-compatible-simd-t = see below;
Let x denote an lvalue of type const T.
make-compatible-simd-t<V, T> is an alias for
  • deduced-simd-t<T>, if that type is not void, otherwise
  • simd<decltype(x + x), V​::​size()>.
template<class... Ts> requires math-floating-point<Ts...> using math-common-simd-t = see below;
Let T0 denote Ts...[0].
Let T1 denote Ts...[1].
Let TRest denote a pack such that T0, T1, TRest... is equivalent to Ts....
Let math-common-simd-t<Ts...> be an alias for
  • deduced-simd-t<T0>, if sizeof...(Ts) equals 1; otherwise
  • common_type_t<deduced-simd-t<T0>, deduced-simd-t<T1>>, if sizeof...(Ts) equals 2 and math-floating-point<T0> && math-floating-point<T1> is true; otherwise
  • common_type_t<deduced-simd-t<T0>, T1>, if sizeof...(Ts) equals 2 and math-floating-​point<​T0> is true; otherwise
  • common_type_t<T0, deduced-simd-t<T1>>, if sizeof...(Ts) equals 2; otherwise
  • common_type_t<math-common-simd-t<T0, T1>, TRest...>, if math-common-simd-t<T0, T1> is valid and denotes a type; otherwise
  • common_type_t<math-common-simd-t<TRest...>, T0, T1>.
template<class BinaryOperation, class T> concept reduction-binary-operation = requires (const BinaryOperation binary_op, const simd<T, 1> v) { { binary_op(v, v) } -> same_as<simd<T, 1>>; };
Types BinaryOperation and T model reduction-binary-operation<BinaryOperation, T> only if:
  • BinaryOperation is a binary element-wise operation and the operation is commutative.
  • An object of type BinaryOperation can be invoked with two arguments of type basic_simd<T, Abi>, with unspecified ABI tag Abi, returning a basic_simd<T, Abi>.

29.10.2.2 simd ABI tags [simd.expos.abi]

template<class T> using native-abi = see below; template<class T, simd-size-type N> using deduce-abi-t = see below;
An ABI tag is a type that indicates a choice of size and binary representation for objects of data-parallel type.
[Note 1: 
The intent is for the size and binary representation to depend on the target architecture and compiler flags.
The ABI tag, together with a given element type, implies the width.
— end note]
[Note 2: 
The ABI tag is orthogonal to selecting the machine instruction set.
The selected machine instruction set limits the usable ABI tag types, though (see [simd.overview]).
The ABI tags enable users to safely pass objects of data-parallel type between translation unit boundaries (e.g., function calls or I/O).
— end note]
An implementation defines ABI tag types as necessary for the following aliases.
deduce-abi-t<T, N> is defined if
  • T is a vectorizable type,
  • N is greater than zero, and
  • N is not larger than an implementation-defined maximum.
The implementation-defined maximum for N is not smaller than 64 and can differ depending on T.
Where present, deduce-abi-t<T, N> names an ABI tag type such that
  • simd-size-v<T, deduce-abi-t<T, N>> equals N,
  • basic_simd<T, deduce-abi-t<T, N>> is enabled ([simd.overview]), and
  • basic_simd_mask<sizeof(T), deduce-abi-t<integer-from<sizeof(T)>, N>> is enabled.
native-abi<T> is an implementation-defined alias for an ABI tag.
basic_simd<T, native-abi<T>> is an enabled specialization.
[Note 3: 
The intent is to use the ABI tag producing the most efficient data-parallel execution for the element type T on the currently targeted system.
For target architectures with ISA extensions, compiler flags can change the type of the native-abi<T> alias.
— end note]
[Example 1: 
Consider a target architecture supporting the ABI tags __simd128 and __simd256, where hardware support for __simd256 exists only for floating-point types.
The implementation therefore defines native-abi<T> as an alias for
  • __simd256 if T is a floating-point type, and
  • __simd128 otherwise.
— end example]

29.10.3 Header <simd> synopsis [simd.syn]

namespace std { // [simd.traits], simd type traits template<class T, class U = typename T::value_type> struct simd_alignment; template<class T, class U = typename T::value_type> constexpr size_t simd_alignment_v = simd_alignment<T, U>::value; template<class T, class V> struct rebind_simd { using type = see below; }; template<class T, class V> using rebind_simd_t = typename rebind_simd<T, V>::type; template<simd-size-type N, class V> struct resize_simd { using type = see below; }; template<simd-size-type N, class V> using resize_simd_t = typename resize_simd<N, V>::type; // [simd.flags], Load and store flags template<class... Flags> struct simd_flags; inline constexpr simd_flags<> simd_flag_default{}; inline constexpr simd_flags<convert-flag> simd_flag_convert{}; inline constexpr simd_flags<aligned-flag> simd_flag_aligned{}; template<size_t N> requires (has_single_bit(N)) constexpr simd_flags<overaligned-flag<N>> simd_flag_overaligned{}; // [simd.class], Class template basic_simd template<class T, class Abi = native-abi<T>> class basic_simd; template<class T, simd-size-type N = simd-size-v<T, native-abi<T>>> using simd = basic_simd<T, deduce-abi-t<T, N>>; // [simd.mask.class], Class template basic_simd_mask template<size_t Bytes, class Abi = native-abi<integer-from<Bytes>>> class basic_simd_mask; template<class T, simd-size-type N = simd-size-v<T, native-abi<T>>> using simd_mask = basic_simd_mask<sizeof(T), deduce-abi-t<T, N>>; // [simd.loadstore], basic_simd load and store functions template<class V = see below, ranges::contiguous_range R, class... Flags> requires ranges::sized_range<R> constexpr V simd_unchecked_load(R&& r, simd_flags<Flags...> f = {}); template<class V = see below, ranges::contiguous_range R, class... Flags> requires ranges::sized_range<R> constexpr V simd_unchecked_load(R&& r, const typename V::mask_type& k, simd_flags<Flags...> f = {}); template<class V = see below, contiguous_iterator I, class... Flags> constexpr V simd_unchecked_load(I first, iter_difference_t<I> n, simd_flags<Flags...> f = {}); template<class V = see below, contiguous_iterator I, class... Flags> constexpr V simd_unchecked_load(I first, iter_difference_t<I> n, const typename V::mask_type& k, simd_flags<Flags...> f = {}); template<class V = see below, contiguous_iterator I, sized_sentinel_for<I> S, class... Flags> constexpr V simd_unchecked_load(I first, S last, simd_flags<Flags...> f = {}); template<class V = see below, contiguous_iterator I, sized_sentinel_for<I> S, class... Flags> constexpr V simd_unchecked_load(I first, S last, const typename V::mask_type& k, simd_flags<Flags...> f = {}); template<class V = see below, ranges::contiguous_range R, class... Flags> requires ranges::sized_range<R> constexpr V simd_partial_load(R&& r, simd_flags<Flags...> f = {}); template<class V = see below, ranges::contiguous_range R, class... Flags> requires ranges::sized_range<R> constexpr V simd_partial_load(R&& r, const typename V::mask_type& k, simd_flags<Flags...> f = {}); template<class V = see below, contiguous_iterator I, class... Flags> constexpr V simd_partial_load(I first, iter_difference_t<I> n, simd_flags<Flags...> f = {}); template<class V = see below, contiguous_iterator I, class... Flags> constexpr V simd_partial_load(I first, iter_difference_t<I> n, const typename V::mask_type& k, simd_flags<Flags...> f = {}); template<class V = see below, contiguous_iterator I, sized_sentinel_for<I> S, class... Flags> constexpr V simd_partial_load(I first, S last, simd_flags<Flags...> f = {}); template<class V = see below, contiguous_iterator I, sized_sentinel_for<I> S, class... Flags> constexpr V simd_partial_load(I first, S last, const typename V::mask_type& k, simd_flags<Flags...> f = {}); template<class T, class Abi, ranges::contiguous_range R, class... Flags> requires ranges::sized_range<R> && indirectly_writable<ranges::iterator_t<R>, T> constexpr void simd_unchecked_store(const basic_simd<T, Abi>& v, R&& r, simd_flags<Flags...> f = {}); template<class T, class Abi, ranges::contiguous_range R, class... Flags> requires ranges::sized_range<R> && indirectly_writable<ranges::iterator_t<R>, T> constexpr void simd_unchecked_store(const basic_simd<T, Abi>& v, R&& r, const typename basic_simd<T, Abi>::mask_type& mask, simd_flags<Flags...> f = {}); template<class T, class Abi, contiguous_iterator I, class... Flags> requires indirectly_writable<I, T> constexpr void simd_unchecked_store(const basic_simd<T, Abi>& v, I first, iter_difference_t<I> n, simd_flags<Flags...> f = {}); template<class T, class Abi, contiguous_iterator I, class... Flags> requires indirectly_writable<I, T> constexpr void simd_unchecked_store(const basic_simd<T, Abi>& v, I first, iter_difference_t<I> n, const typename basic_simd<T, Abi>::mask_type& mask, simd_flags<Flags...> f = {}); template<class T, class Abi, contiguous_iterator I, sized_sentinel_for<I> S, class... Flags> requires indirectly_writable<I, T> constexpr void simd_unchecked_store(const basic_simd<T, Abi>& v, I first, S last, simd_flags<Flags...> f = {}); template<class T, class Abi, contiguous_iterator I, sized_sentinel_for<I> S, class... Flags> requires indirectly_writable<I, T> constexpr void simd_unchecked_store(const basic_simd<T, Abi>& v, I first, S last, const typename basic_simd<T, Abi>::mask_type& mask, simd_flags<Flags...> f = {}); template<class T, class Abi, ranges::contiguous_range R, class... Flags> requires ranges::sized_range<R> && indirectly_writable<ranges::iterator_t<R>, T> constexpr void simd_partial_store(const basic_simd<T, Abi>& v, R&& r, simd_flags<Flags...> f = {}); template<class T, class Abi, ranges::contiguous_range R, class... Flags> requires ranges::sized_range<R> && indirectly_writable<ranges::iterator_t<R>, T> constexpr void simd_partial_store(const basic_simd<T, Abi>& v, R&& r, const typename basic_simd<T, Abi>::mask_type& mask, simd_flags<Flags...> f = {}); template<class T, class Abi, contiguous_iterator I, class... Flags> requires indirectly_writable<I, T> constexpr void simd_partial_store( const basic_simd<T, Abi>& v, I first, iter_difference_t<I> n, simd_flags<Flags...> f = {}); template<class T, class Abi, contiguous_iterator I, class... Flags> requires indirectly_writable<I, T> constexpr void simd_partial_store( const basic_simd<T, Abi>& v, I first, iter_difference_t<I> n, const typename basic_simd<T, Abi>::mask_type& mask, simd_flags<Flags...> f = {}); template<class T, class Abi, contiguous_iterator I, sized_sentinel_for<I> S, class... Flags> requires indirectly_writable<I, T> constexpr void simd_partial_store(const basic_simd<T, Abi>& v, I first, S last, simd_flags<Flags...> f = {}); template<class T, class Abi, contiguous_iterator I, sized_sentinel_for<I> S, class... Flags> requires indirectly_writable<I, T> constexpr void simd_partial_store(const basic_simd<T, Abi>& v, I first, S last, const typename basic_simd<T, Abi>::mask_type& mask, simd_flags<Flags...> f = {}); // [simd.creation], basic_simd and basic_simd_mask creation template<class T, class Abi> constexpr auto simd_split(const basic_simd<typename T::value_type, Abi>& x) noexcept; template<class T, class Abi> constexpr auto simd_split(const basic_simd_mask<mask-element-size<T>, Abi>& x) noexcept; template<class T, class... Abis> constexpr basic_simd<T, deduce-abi-t<T, (basic_simd<T, Abis>::size() + ...)>> simd_cat(const basic_simd<T, Abis>&...) noexcept; template<size_t Bytes, class... Abis> constexpr basic_simd_mask<Bytes, deduce-abi-t<integer-from<Bytes>, (basic_simd_mask<Bytes, Abis>::size() + ...)>> simd_cat(const basic_simd_mask<Bytes, Abis>&...) noexcept; // [simd.mask.reductions], basic_simd_mask reductions template<size_t Bytes, class Abi> constexpr bool all_of(const basic_simd_mask<Bytes, Abi>&) noexcept; template<size_t Bytes, class Abi> constexpr bool any_of(const basic_simd_mask<Bytes, Abi>&) noexcept; template<size_t Bytes, class Abi> constexpr bool none_of(const basic_simd_mask<Bytes, Abi>&) noexcept; template<size_t Bytes, class Abi> constexpr simd-size-type reduce_count(const basic_simd_mask<Bytes, Abi>&) noexcept; template<size_t Bytes, class Abi> constexpr simd-size-type reduce_min_index(const basic_simd_mask<Bytes, Abi>&); template<size_t Bytes, class Abi> constexpr simd-size-type reduce_max_index(const basic_simd_mask<Bytes, Abi>&); constexpr bool all_of(same_as<bool> auto) noexcept; constexpr bool any_of(same_as<bool> auto) noexcept; constexpr bool none_of(same_as<bool> auto) noexcept; constexpr simd-size-type reduce_count(same_as<bool> auto) noexcept; constexpr simd-size-type reduce_min_index(same_as<bool> auto); constexpr simd-size-type reduce_max_index(same_as<bool> auto); // [simd.reductions], basic_simd reductions template<class T, class Abi, class BinaryOperation = plus<>> constexpr T reduce(const basic_simd<T, Abi>&, BinaryOperation = {}); template<class T, class Abi, class BinaryOperation = plus<>> constexpr T reduce( const basic_simd<T, Abi>& x, const typename basic_simd<T, Abi>::mask_type& mask, BinaryOperation binary_op = {}, type_identity_t<T> identity_element = see below); template<class T, class Abi> constexpr T reduce_min(const basic_simd<T, Abi>&) noexcept; template<class T, class Abi> constexpr T reduce_min(const basic_simd<T, Abi>&, const typename basic_simd<T, Abi>::mask_type&) noexcept; template<class T, class Abi> constexpr T reduce_max(const basic_simd<T, Abi>&) noexcept; template<class T, class Abi> constexpr T reduce_max(const basic_simd<T, Abi>&, const typename basic_simd<T, Abi>::mask_type&) noexcept; // [simd.alg], Algorithms template<class T, class Abi> constexpr basic_simd<T, Abi> min(const basic_simd<T, Abi>& a, const basic_simd<T, Abi>& b) noexcept; template<class T, class Abi> constexpr basic_simd<T, Abi> max(const basic_simd<T, Abi>& a, const basic_simd<T, Abi>& b) noexcept; template<class T, class Abi> constexpr pair<basic_simd<T, Abi>, basic_simd<T, Abi>> minmax(const basic_simd<T, Abi>& a, const basic_simd<T, Abi>& b) noexcept; template<class T, class Abi> constexpr basic_simd<T, Abi> clamp(const basic_simd<T, Abi>& v, const basic_simd<T, Abi>& lo, const basic_simd<T, Abi>& hi); template<class T, class U> constexpr auto simd_select(bool c, const T& a, const U& b) -> remove_cvref_t<decltype(c ? a : b)>; template<size_t Bytes, class Abi, class T, class U> constexpr auto simd_select(const basic_simd_mask<Bytes, Abi>& c, const T& a, const U& b) noexcept -> decltype(simd-select-impl(c, a, b)); // [simd.math], Mathematical functions template<math-floating-point V> constexpr deduced-simd-t<V> acos(const V& x); template<math-floating-point V> constexpr deduced-simd-t<V> asin(const V& x); template<math-floating-point V> constexpr deduced-simd-t<V> atan(const V& x); template<class V0, class V1> constexpr math-common-simd-t<V0, V1> atan2(const V0& y, const V1& x); template<math-floating-point V> constexpr deduced-simd-t<V> cos(const V& x); template<math-floating-point V> constexpr deduced-simd-t<V> sin(const V& x); template<math-floating-point V> constexpr deduced-simd-t<V> tan(const V& x); template<math-floating-point V> constexpr deduced-simd-t<V> acosh(const V& x); template<math-floating-point V> constexpr deduced-simd-t<V> asinh(const V& x); template<math-floating-point V> constexpr deduced-simd-t<V> atanh(const V& x); template<math-floating-point V> constexpr deduced-simd-t<V> cosh(const V& x); template<math-floating-point V> constexpr deduced-simd-t<V> sinh(const V& x); template<math-floating-point V> constexpr deduced-simd-t<V> tanh(const V& x); template<math-floating-point V> constexpr deduced-simd-t<V> exp(const V& x); template<math-floating-point V> constexpr deduced-simd-t<V> exp2(const V& x); template<math-floating-point V> constexpr deduced-simd-t<V> expm1(const V& x); template<math-floating-point V> constexpr deduced-simd-t<V> frexp(const V& value, rebind_simd_t<int, deduced-simd-t<V>>* exp); template<math-floating-point V> constexpr rebind_simd_t<int, deduced-simd-t<V>> ilogb(const V& x); template<math-floating-point V> constexpr deduced-simd-t<V> ldexp(const V& x, const rebind_simd_t<int, deduced-simd-t<V>>& exp); template<math-floating-point V> constexpr deduced-simd-t<V> log(const V& x); template<math-floating-point V> constexpr deduced-simd-t<V> log10(const V& x); template<math-floating-point V> constexpr deduced-simd-t<V> log1p(const V& x); template<math-floating-point V> constexpr deduced-simd-t<V> log2(const V& x); template<math-floating-point V> constexpr deduced-simd-t<V> logb(const V& x); template<class T, class Abi> constexpr basic_simd<T, Abi> modf(const type_identity_t<basic_simd<T, Abi>>& value, basic_simd<T, Abi>* iptr); template<math-floating-point V> constexpr deduced-simd-t<V> scalbn(const V& x, const rebind_simd_t<int, deduced-simd-t<V>>& n); template<math-floating-point V> constexpr deduced-simd-t<V> scalbln( const V& x, const rebind_simd_t<long int, deduced-simd-t<V>>& n); template<math-floating-point V> constexpr deduced-simd-t<V> cbrt(const V& x); template<signed_integral T, class Abi> constexpr basic_simd<T, Abi> abs(const basic_simd<T, Abi>& j); template<math-floating-point V> constexpr deduced-simd-t<V> abs(const V& j); template<math-floating-point V> constexpr deduced-simd-t<V> fabs(const V& x); template<class V0, class V1> constexpr math-common-simd-t<V0, V1> hypot(const V0& x, const V1& y); template<class V0, class V1, class V2> constexpr math-common-simd-t<V0, V1, V2> hypot(const V0& x, const V1& y, const V2& z); template<class V0, class V1> constexpr math-common-simd-t<V0, V1> pow(const V0& x, const V1& y); template<math-floating-point V> constexpr deduced-simd-t<V> sqrt(const V& x); template<math-floating-point V> constexpr deduced-simd-t<V> erf(const V& x); template<math-floating-point V> constexpr deduced-simd-t<V> erfc(const V& x); template<math-floating-point V> constexpr deduced-simd-t<V> lgamma(const V& x); template<math-floating-point V> constexpr deduced-simd-t<V> tgamma(const V& x); template<math-floating-point V> constexpr deduced-simd-t<V> ceil(const V& x); template<math-floating-point V> constexpr deduced-simd-t<V> floor(const V& x); template<math-floating-point V> deduced-simd-t<V> nearbyint(const V& x); template<math-floating-point V> deduced-simd-t<V> rint(const V& x); template<math-floating-point V> rebind_simd_t<long int, deduced-simd-t<V>> lrint(const V& x); template<math-floating-point V> rebind_simd_t<long long int, V> llrint(const deduced-simd-t<V>& x); template<math-floating-point V> constexpr deduced-simd-t<V> round(const V& x); template<math-floating-point V> constexpr rebind_simd_t<long int, deduced-simd-t<V>> lround(const V& x); template<math-floating-point V> constexpr rebind_simd_t<long long int, deduced-simd-t<V>> llround(const V& x); template<math-floating-point V> constexpr deduced-simd-t<V> trunc(const V& x); template<class V0, class V1> constexpr math-common-simd-t<V0, V1> fmod(const V0& x, const V1& y); template<class V0, class V1> constexpr math-common-simd-t<V0, V1> remainder(const V0& x, const V1& y); template<class V0, class V1> constexpr math-common-simd-t<V0, V1> remquo(const V0& x, const V1& y, rebind_simd_t<int, math-common-simd-t<V0, V1>>* quo); template<class V0, class V1> constexpr math-common-simd-t<V0, V1> copysign(const V0& x, const V1& y); template<class V0, class V1> constexpr math-common-simd-t<V0, V1> nextafter(const V0& x, const V1& y); template<class V0, class V1> constexpr math-common-simd-t<V0, V1> fdim(const V0& x, const V1& y); template<class V0, class V1> constexpr math-common-simd-t<V0, V1> fmax(const V0& x, const V1& y); template<class V0, class V1> constexpr math-common-simd-t<V0, V1> fmin(const V0& x, const V1& y); template<class V0, class V1, class V2> constexpr math-common-simd-t<V0, V1, V2> fma(const V0& x, const V1& y, const V2& z); template<class V0, class V1, class V2> constexpr math-common-simd-t<V0, V1, V2> lerp(const V0& a, const V1& b, const V2& t) noexcept; template<math-floating-point V> constexpr rebind_simd_t<int, deduced-simd-t<V>> fpclassify(const V& x); template<math-floating-point V> constexpr typename deduced-simd-t<V>::mask_type isfinite(const V& x); template<math-floating-point V> constexpr typename deduced-simd-t<V>::mask_type isinf(const V& x); template<math-floating-point V> constexpr typename deduced-simd-t<V>::mask_type isnan(const V& x); template<math-floating-point V> constexpr typename deduced-simd-t<V>::mask_type isnormal(const V& x); template<math-floating-point V> constexpr typename deduced-simd-t<V>::mask_type signbit(const V& x); template<class V0, class V1> constexpr typename math-common-simd-t<V0, V1>::mask_type isgreater(const V0& x, const V1& y); template<class V0, class V1> constexpr typename math-common-simd-t<V0, V1>::mask_type isgreaterequal(const V0& x, const V1& y); template<class V0, class V1> constexpr typename math-common-simd-t<V0, V1>::mask_type isless(const V0& x, const V1& y); template<class V0, class V1> constexpr typename math-common-simd-t<V0, V1>::mask_type islessequal(const V0& x, const V1& y); template<class V0, class V1> constexpr typename math-common-simd-t<V0, V1>::mask_type islessgreater(const V0& x, const V1& y); template<class V0, class V1> constexpr typename math-common-simd-t<V0, V1>::mask_type isunordered(const V0& x, const V1& y); template<math-floating-point V> deduced-simd-t<V> assoc_laguerre(const rebind_simd_t<unsigned, deduced-simd-t<V>>& n, const rebind_simd_t<unsigned, deduced-simd-t<V>>& m, const V& x); template<math-floating-point V> deduced-simd-t<V> assoc_legendre(const rebind_simd_t<unsigned, deduced-simd-t<V>>& l, const rebind_simd_t<unsigned, deduced-simd-t<V>>& m, const V& x); template<class V0, class V1> math-common-simd-t<V0, V1> beta(const V0& x, const V1& y); template<math-floating-point V> deduced-simd-t<V> comp_ellint_1(const V& k); template<math-floating-point V> deduced-simd-t<V> comp_ellint_2(const V& k); template<class V0, class V1> math-common-simd-t<V0, V1> comp_ellint_3(const V0& k, const V1& nu); template<class V0, class V1> math-common-simd-t<V0, V1> cyl_bessel_i(const V0& nu, const V1& x); template<class V0, class V1> math-common-simd-t<V0, V1> cyl_bessel_j(const V0& nu, const V1& x); template<class V0, class V1> math-common-simd-t<V0, V1> cyl_bessel_k(const V0& nu, const V1& x); template<class V0, class V1> math-common-simd-t<V0, V1> cyl_neumann(const V0& nu, const V1& x); template<class V0, class V1> math-common-simd-t<V0, V1> ellint_1(const V0& k, const V1& phi); template<class V0, class V1> math-common-simd-t<V0, V1> ellint_2(const V0& k, const V1& phi); template<class V0, class V1, class V2> math-common-simd-t<V0, V1, V2> ellint_3(const V0& k, const V1& nu, const V2& phi); template<math-floating-point V> deduced-simd-t<V> expint(const V& x); template<math-floating-point V> deduced-simd-t<V> hermite(const rebind_simd_t<unsigned, deduced-simd-t<V>>& n, const V& x); template<math-floating-point V> deduced-simd-t<V> laguerre(const rebind_simd_t<unsigned, deduced-simd-t<V>>& n, const V& x); template<math-floating-point V> deduced-simd-t<V> legendre(const rebind_simd_t<unsigned, deduced-simd-t<V>>& l, const V& x); template<math-floating-point V> deduced-simd-t<V> riemann_zeta(const V& x); template<math-floating-point V> deduced-simd-t<V> sph_bessel( const rebind_simd_t<unsigned, deduced-simd-t<V>>& n, const V& x); template<math-floating-point V> deduced-simd-t<V> sph_legendre(const rebind_simd_t<unsigned, deduced-simd-t<V>>& l, const rebind_simd_t<unsigned, deduced-simd-t<V>>& m, const V& theta); template<math-floating-point V> deduced-simd-t<V> sph_neumann(const rebind_simd_t<unsigned, deduced-simd-t<V>>& n, const V& x); }

29.10.4 simd type traits [simd.traits]

template<class T, class U = typename T::value_type> struct simd_alignment { see below };
simd_alignment<T, U> has a member value if and only if
  • T is a specialization of basic_simd_mask and U is bool, or
  • T is a specialization of basic_simd and U is a vectorizable type.
If value is present, the type simd_alignment<T, U> is a BinaryTypeTrait with a base characteristic of integral_constant<size_t, N> for some unspecified N ([simd.ctor], [simd.loadstore])).
[Note 1: 
value identifies the alignment restrictions on pointers used for (converting) loads and stores for the given type T on arrays of type U.
— end note]
The behavior of a program that adds specializations for simd_alignment is undefined.
template<class T, class V> struct rebind_simd { using type = see below; };
The member type is present if and only if
  • V is a data-parallel type,
  • T is a vectorizable type, and
  • deduce-abi-t<T, V​::​size()> has a member type type.
If V is a specialization of basic_simd, let Abi1 denote an ABI tag such that basic_simd<T, Abi1>​::​​size() equals V​::​size().
If V is a specialization of basic_simd_mask, let Abi1 denote an ABI tag such that basic_simd_mask<sizeof(T), Abi1>​::​​size() equals V​::​size().
Where present, the member typedef type names basic_simd<T, Abi1> if V is a specialization of basic_simd or basic_simd_mask<sizeof(T), Abi1> if V is a specialization of basic_simd_mask.
template<simd-size-type N, class V> struct resize_simd { using type = see below; };
Let T denote
  • typename V​::​value_type if V is a specialization of basic_simd,
  • otherwise integer-from<mask-element-size<V>> if V is a specialization of basic_simd_mask.
The member type is present if and only if
  • V is a data-parallel type, and
  • deduce-abi-t<T, N> has a member type type.
If V is a specialization of basic_simd, let Abi1 denote an ABI tag such that basic_simd<T, Abi1>​::​​size() equals V​::​size().
If V is a specialization of basic_simd_mask, let Abi1 denote an ABI tag such that basic_simd_mask<sizeof(T), Abi1>​::​​size() equals V​::​size().
Where present, the member typedef type names basic_simd<T, Abi1> if V is a specialization of basic_simd or basic_simd_mask<sizeof(T), Abi1> if V is a specialization of basic_simd_mask.

29.10.5 Load and store flags [simd.flags]

29.10.5.1 Class template simd_flags overview [simd.flags.overview]

namespace std { template<class... Flags> struct simd_flags { // [simd.flags.oper], simd_flags operators template<class... Other> friend consteval auto operator|(simd_flags, simd_flags<Other...>); }; }
[Note 1: 
The class template simd_flags acts like an integer bit-flag for types.
— end note]
Constraints: Every type in the parameter pack Flags is one of convert-flag, aligned-flag, or overaligned-​flag<N>.

29.10.5.2 simd_flags operators [simd.flags.oper]

template<class... Other> friend consteval auto operator|(simd_flags a, simd_flags<Other...> b);
Returns: A default-initialized object of type simd_flags<Flags2...> for some Flags2 where every type in Flags2 is present either in template parameter pack Flags or in template parameter pack Other, and every type in template parameter packs Flags and Other is present in Flags2.
If the packs Flags and Other contain two different specializations overaligned-flag<N1> and overaligned-flag<N2>, Flags2 is not required to contain the specialization overaligned-flag<std​::​min(N1, N2)>.

29.10.6 Class template basic_simd [simd.class]

29.10.6.1 Class template basic_simd overview [simd.overview]

namespace std { template<class T, class Abi> class basic_simd { public: using value_type = T; using mask_type = basic_simd_mask<sizeof(T), Abi>; using abi_type = Abi; static constexpr integral_constant<simd-size-type, simd-size-v<T, Abi>> size {}; constexpr basic_simd() noexcept = default; // [simd.ctor], basic_simd constructors template<class U> constexpr basic_simd(U&& value) noexcept; template<class U, class UAbi> constexpr explicit(see below) basic_simd(const basic_simd<U, UAbi>&) noexcept; template<class G> constexpr explicit basic_simd(G&& gen) noexcept; template<class R, class... Flags> constexpr basic_simd(R&& range, simd_flags<Flags...> = {}); template<class R, class... Flags> constexpr basic_simd(R&& range, const mask_type& mask, simd_flags<Flags...> = {}); // [simd.subscr], basic_simd subscript operators constexpr value_type operator[](simd-size-type) const; // [simd.unary], basic_simd unary operators constexpr basic_simd& operator++() noexcept; constexpr basic_simd operator++(int) noexcept; constexpr basic_simd& operator--() noexcept; constexpr basic_simd operator--(int) noexcept; constexpr mask_type operator!() const noexcept; constexpr basic_simd operator~() const noexcept; constexpr basic_simd operator+() const noexcept; constexpr basic_simd operator-() const noexcept; // [simd.binary], basic_simd binary operators friend constexpr basic_simd operator+(const basic_simd&, const basic_simd&) noexcept; friend constexpr basic_simd operator-(const basic_simd&, const basic_simd&) noexcept; friend constexpr basic_simd operator*(const basic_simd&, const basic_simd&) noexcept; friend constexpr basic_simd operator/(const basic_simd&, const basic_simd&) noexcept; friend constexpr basic_simd operator%(const basic_simd&, const basic_simd&) noexcept; friend constexpr basic_simd operator&(const basic_simd&, const basic_simd&) noexcept; friend constexpr basic_simd operator|(const basic_simd&, const basic_simd&) noexcept; friend constexpr basic_simd operator^(const basic_simd&, const basic_simd&) noexcept; friend constexpr basic_simd operator<<(const basic_simd&, const basic_simd&) noexcept; friend constexpr basic_simd operator>>(const basic_simd&, const basic_simd&) noexcept; friend constexpr basic_simd operator<<(const basic_simd&, simd-size-type) noexcept; friend constexpr basic_simd operator>>(const basic_simd&, simd-size-type) noexcept; // [simd.cassign], basic_simd compound assignment friend constexpr basic_simd& operator+=(basic_simd&, const basic_simd&) noexcept; friend constexpr basic_simd& operator-=(basic_simd&, const basic_simd&) noexcept; friend constexpr basic_simd& operator*=(basic_simd&, const basic_simd&) noexcept; friend constexpr basic_simd& operator/=(basic_simd&, const basic_simd&) noexcept; friend constexpr basic_simd& operator%=(basic_simd&, const basic_simd&) noexcept; friend constexpr basic_simd& operator&=(basic_simd&, const basic_simd&) noexcept; friend constexpr basic_simd& operator|=(basic_simd&, const basic_simd&) noexcept; friend constexpr basic_simd& operator^=(basic_simd&, const basic_simd&) noexcept; friend constexpr basic_simd& operator<<=(basic_simd&, const basic_simd&) noexcept; friend constexpr basic_simd& operator>>=(basic_simd&, const basic_simd&) noexcept; friend constexpr basic_simd& operator<<=(basic_simd&, simd-size-type) noexcept; friend constexpr basic_simd& operator>>=(basic_simd&, simd-size-type) noexcept; // [simd.comparison], basic_simd compare operators friend constexpr mask_type operator==(const basic_simd&, const basic_simd&) noexcept; friend constexpr mask_type operator!=(const basic_simd&, const basic_simd&) noexcept; friend constexpr mask_type operator>=(const basic_simd&, const basic_simd&) noexcept; friend constexpr mask_type operator<=(const basic_simd&, const basic_simd&) noexcept; friend constexpr mask_type operator>(const basic_simd&, const basic_simd&) noexcept; friend constexpr mask_type operator<(const basic_simd&, const basic_simd&) noexcept; // [simd.cond], basic_simd exposition only conditional operators friend constexpr basic_simd simd-select-impl( // exposition only const mask_type&, const basic_simd&, const basic_simd&) noexcept; }; template<class R, class... Ts> basic_simd(R&& r, Ts...) -> see below; }
Every specialization of basic_simd is a complete type.
The specialization of basic_simd<T, Abi> is
  • enabled, if T is a vectorizable type, and there exists value N in the range [1, 64], such that Abi is deduce-abi-t<T, N>,
  • otherwise, disabled, if T is not a vectorizable type,
  • otherwise, it is implementation-defined if such a specialization is enabled.
If basic_simd<T, Abi> is disabled, the specialization has a deleted default constructor, deleted destructor, deleted copy constructor, and deleted copy assignment.
In addition only the value_type, abi_type, and mask_type members are present.
If basic_simd<T, Abi> is enabled, basic_simd<T, Abi> is trivially copyable.
Recommended practice: Implementations should support explicit conversions between specializations of basic_simd and appropriate implementation-defined types.
[Note 1: 
Appropriate types are non-standard vector types which are available in the implementation.
— end note]

29.10.6.2 basic_simd constructors [simd.ctor]

template<class U> constexpr basic_simd(U&&) noexcept;
Let From denote the type remove_cvref_t<U>.
Constraints: From satisfies convertible_to<value_type>, and either
Effects: Initializes each element to the value of the argument after conversion to value_type.
template<class U, class UAbi> constexpr explicit(see below) basic_simd(const basic_simd<U, UAbi>& x) noexcept;
Constraints: simd-size-v<U, UAbi> == size() is true.
Effects: Initializes the element with static_cast<T>(x[i]) for all i in the range of [0, size()).
Remarks: The expression inside explicit evaluates to true if either
  • the conversion from U to value_type is not value-preserving, or
  • both U and value_type are integral types and the integer conversion rank ([conv.rank]) of U is greater than the integer conversion rank of value_type, or
  • both U and value_type are floating-point types and the floating-point conversion rank ([conv.rank]) of U is greater than the floating-point conversion rank of value_type.
template<class G> constexpr explicit basic_simd(G&& gen) noexcept;
Let From denote the type decltype(gen(integral_constant<simd-size-type, i>())).
Constraints: From satisfies convertible_to<value_type> for all i in the range of [0, size()).
In addition, for all i in the range of [0, size()), if From is an arithmetic type, conversion from From to value_type is value-preserving.
Effects: Initializes the element with static_cast<value_type>(gen(integral_constant<simd-​size-​type, i>())) for all i in the range of [0, size()).
Remarks: The calls to gen are unsequenced with respect to each other.
Vectorization-unsafe ([algorithms.parallel.defns]) standard library functions may not be invoked by gen.
gen is invoked exactly once for each i.
template<class R, class... Flags> constexpr basic_simd(R&& r, simd_flags<Flags...> = {}); template<class R, class... Flags> constexpr basic_simd(R&& r, const mask_type& mask, simd_flags<Flags...> = {});
Let mask be mask_type(true) for the overload with no mask parameter.
Constraints:
  • R models ranges​::​contiguous_range and ranges​::​sized_range,
  • ranges​::​size(r) is a constant expression, and
  • ranges​::​size(r) is equal to size().
Mandates:
  • ranges​::​range_value_t<R> is a vectorizable type, and
  • if the template parameter pack Flags does not contain convert-flag, then the conversion from ranges​::​range_value_t<R> to value_type is value-preserving.
Preconditions:
  • If the template parameter pack Flags contains aligned-flag, ranges​::​data(range) points to storage aligned by simd_alignment_v<basic_simd, ranges​::​range_value_t<R>>.
  • If the template parameter pack Flags contains overaligned-flag<N>, ranges​::​data(range) points to storage aligned by N.
Effects: Initializes the element with mask[i] ? static_cast<T>(​ranges​::​​data(range)[i]) : T() for all i in the range of [0, size()).
template<class R, class... Ts> basic_simd(R&& r, Ts...) -> see below;
Constraints:
  • R models ranges​::​contiguous_range and ranges​::​sized_range, and
  • ranges​::​size(r) is a constant expression.
Remarks: The deduced type is equivalent to simd<ranges​::​range_value_t<R>, ranges​::​size(r)>.

29.10.6.3 basic_simd subscript operator [simd.subscr]

constexpr value_type operator[](simd-size-type i) const;
Preconditions: i >= 0 && i < size() is true.
Returns: The value of the element.
Throws: Nothing.

29.10.6.4 basic_simd unary operators [simd.unary]

Effects in [simd.unary] are applied as unary element-wise operations.
constexpr basic_simd& operator++() noexcept;
Constraints: requires (value_type a) { ++a; } is true.
Effects: Increments every element by one.
Returns: *this.
constexpr basic_simd operator++(int) noexcept;
Constraints: requires (value_type a) { a++; } is true.
Effects: Increments every element by one.
Returns: A copy of *this before incrementing.
constexpr basic_simd& operator--() noexcept;
Constraints: requires (value_type a) { --a; } is true.
Effects: Decrements every element by one.
Returns: *this.
constexpr basic_simd operator--(int) noexcept;
Constraints: requires (value_type a) { a--; } is true.
Effects: Decrements every element by one.
Returns: A copy of *this before decrementing.
constexpr mask_type operator!() const noexcept;
Constraints: requires (const value_type a) { !a; } is true.
Returns: A basic_simd_mask object with the element set to !operator[](i) for all i in the range of [0, size()).
constexpr basic_simd operator~() const noexcept;
Constraints: requires (const value_type a) { ~a; } is true.
Returns: A basic_simd object with the element set to ~operator[](i) for all i in the range of [0, size()).
constexpr basic_simd operator+() const noexcept;
Constraints: requires (const value_type a) { +a; } is true.
Returns: *this.
constexpr basic_simd operator-() const noexcept;
Constraints: requires (const value_type a) { -a; } is true.
Returns: A basic_simd object where the element is initialized to -operator[](i) for all i in the range of [0, size()).

29.10.7 basic_simd non-member operations [simd.nonmembers]

29.10.7.1 basic_simd binary operators [simd.binary]

friend constexpr basic_simd operator+(const basic_simd& lhs, const basic_simd& rhs) noexcept; friend constexpr basic_simd operator-(const basic_simd& lhs, const basic_simd& rhs) noexcept; friend constexpr basic_simd operator*(const basic_simd& lhs, const basic_simd& rhs) noexcept; friend constexpr basic_simd operator/(const basic_simd& lhs, const basic_simd& rhs) noexcept; friend constexpr basic_simd operator%(const basic_simd& lhs, const basic_simd& rhs) noexcept; friend constexpr basic_simd operator&(const basic_simd& lhs, const basic_simd& rhs) noexcept; friend constexpr basic_simd operator|(const basic_simd& lhs, const basic_simd& rhs) noexcept; friend constexpr basic_simd operator^(const basic_simd& lhs, const basic_simd& rhs) noexcept; friend constexpr basic_simd operator<<(const basic_simd& lhs, const basic_simd& rhs) noexcept; friend constexpr basic_simd operator>>(const basic_simd& lhs, const basic_simd& rhs) noexcept;
Let op be the operator.
Constraints: requires (value_type a, value_type b) { a op b; } is true.
Returns: A basic_simd object initialized with the results of applying op to lhs and rhs as a binary element-wise operation.
friend constexpr basic_simd operator<<(const basic_simd& v, simd-size-type n) noexcept; friend constexpr basic_simd operator>>(const basic_simd& v, simd-size-type n) noexcept;
Let op be the operator.
Constraints: requires (value_type a, simd-size-type b) { a op b; } is true.
Returns: A basic_simd object where the element is initialized to the result of applying op to v[i] and n for all i in the range of [0, size()).

29.10.7.2 basic_simd compound assignment [simd.cassign]

friend constexpr basic_simd& operator+=(basic_simd& lhs, const basic_simd& rhs) noexcept; friend constexpr basic_simd& operator-=(basic_simd& lhs, const basic_simd& rhs) noexcept; friend constexpr basic_simd& operator*=(basic_simd& lhs, const basic_simd& rhs) noexcept; friend constexpr basic_simd& operator/=(basic_simd& lhs, const basic_simd& rhs) noexcept; friend constexpr basic_simd& operator%=(basic_simd& lhs, const basic_simd& rhs) noexcept; friend constexpr basic_simd& operator&=(basic_simd& lhs, const basic_simd& rhs) noexcept; friend constexpr basic_simd& operator|=(basic_simd& lhs, const basic_simd& rhs) noexcept; friend constexpr basic_simd& operator^=(basic_simd& lhs, const basic_simd& rhs) noexcept; friend constexpr basic_simd& operator<<=(basic_simd& lhs, const basic_simd& rhs) noexcept; friend constexpr basic_simd& operator>>=(basic_simd& lhs, const basic_simd& rhs) noexcept;
Let op be the operator.
Constraints: requires (value_type a, value_type b) { a op b; } is true.
Effects: These operators apply the indicated operator to lhs and rhs as an element-wise operation.
Returns: lhs.
friend constexpr basic_simd& operator<<=(basic_simd& lhs, simd-size-type n) noexcept; friend constexpr basic_simd& operator>>=(basic_simd& lhs, simd-size-type n) noexcept;
Let op be the operator.
Constraints: requires (value_type a, simd-size-type b) { a op b; } is true.
Effects: Equivalent to: return operator op (lhs, basic_simd(n));

29.10.7.3 basic_simd compare operators [simd.comparison]

friend constexpr mask_type operator==(const basic_simd& lhs, const basic_simd& rhs) noexcept; friend constexpr mask_type operator!=(const basic_simd& lhs, const basic_simd& rhs) noexcept; friend constexpr mask_type operator>=(const basic_simd& lhs, const basic_simd& rhs) noexcept; friend constexpr mask_type operator<=(const basic_simd& lhs, const basic_simd& rhs) noexcept; friend constexpr mask_type operator>(const basic_simd& lhs, const basic_simd& rhs) noexcept; friend constexpr mask_type operator<(const basic_simd& lhs, const basic_simd& rhs) noexcept;
Let op be the operator.
Constraints: requires (value_type a, value_type b) { a op b; } is true.
Returns: A basic_simd_mask object initialized with the results of applying op to lhs and rhs as a binary element-wise operation.

29.10.7.4 basic_simd exposition only conditional operators [simd.cond]

friend constexpr basic_simd simd-select-impl(const mask_type& mask, const basic_simd& a, const basic_simd& b) noexcept;
Returns: A basic_simd object where the element equals mask[i] ? a[i] : b[i] for all i in the range of [0, size()).

29.10.7.5 basic_simd reductions [simd.reductions]

template<class T, class Abi, class BinaryOperation = plus<>> constexpr T reduce(const basic_simd<T, Abi>& x, BinaryOperation binary_op = {});
Constraints: BinaryOperation models reduction-binary-operation<T>.
Preconditions: binary_op does not modify x.
Returns: GENERALIZED_SUM(binary_op, simd<T, 1>(x[0]), , simd<T, 1>(x[x.size() - 1]))[0] ([numerics.defns]).
Throws: Any exception thrown from binary_op.
template<class T, class Abi, class BinaryOperation = plus<>> constexpr T reduce( const basic_simd<T, Abi>& x, const typename basic_simd<T, Abi>::mask_type& mask, BinaryOperation binary_op = {}, type_identity_t<T> identity_element = see below);
Constraints:
  • BinaryOperation models reduction-binary-operation<T>.
  • An argument for identity_element is provided for the invocation, unless BinaryOperation is one of plus<>, multiplies<>, bit_and<>, bit_or<>, or bit_xor<>.
Preconditions:
  • binary_op does not modify x.
  • For all finite values y representable by T, the results of y == binary_op(simd<T, 1>(identity_element), simd<T, 1>(y))[0] and y == binary_op(simd<T, 1>(y), simd<T, 1>(identity_element))[0] are true.
Returns: If none_of(mask) is true, returns identity_element.
Otherwise, returns GENERALIZED_SUM(binary_op, simd<T, 1>(x[]), , simd<T, 1>(x[]))[0] where are the selected indices of mask.
Throws: Any exception thrown from binary_op.
Remarks: The default argument for identity_element is equal to
  • T() if BinaryOperation is plus<>,
  • T(1) if BinaryOperation is multiplies<>,
  • T(~T()) if BinaryOperation is bit_and<>,
  • T() if BinaryOperation is bit_or<>, or
  • T() if BinaryOperation is bit_xor<>.
template<class T, class Abi> constexpr T reduce_min(const basic_simd<T, Abi>& x) noexcept;
Constraints: T models totally_ordered.
Returns: The value of an element x[j] for which x[i] < x[j] is false for all i in the range of [0, basic_simd<T, Abi>​::​size()).
template<class T, class Abi> constexpr T reduce_min( const basic_simd<T, Abi>&, const typename basic_simd<T, Abi>::mask_type&) noexcept;
Constraints: T models totally_ordered.
Returns: If none_of(mask) is true, returns numeric_limits<T>​::​max().
Otherwise, returns the value of a selected element x[j] for which x[i] < x[j] is false for all selected indices i of mask.
template<class T, class Abi> constexpr T reduce_max(const basic_simd<T, Abi>& x) noexcept;
Constraints: T models totally_ordered.
Returns: The value of an element x[j] for which x[j] < x[i] is false for all i in the range of [0, basic_simd<T, Abi>​::​size()).
template<class T, class Abi> constexpr T reduce_max( const basic_simd<T, Abi>&, const typename basic_simd<T, Abi>::mask_type&) noexcept;
Constraints: T models totally_ordered.
Returns: If none_of(mask) is true, returns numeric_limits<V​::​value_type>​::​lowest().
Otherwise, returns the value of a selected element x[j] for which x[j] < x[i] is false for all selected indices i of mask.

29.10.7.6 basic_simd load and store functions [simd.loadstore]

template<class V = see below, ranges::contiguous_range R, class... Flags> requires ranges::sized_range<R> constexpr V simd_unchecked_load(R&& r, simd_flags<Flags...> f = {}); template<class V = see below, ranges::contiguous_range R, class... Flags> requires ranges::sized_range<R> constexpr V simd_unchecked_load(R&& r, const typename V::mask_type& mask, simd_flags<Flags...> f = {}); template<class V = see below, contiguous_iterator I, class... Flags> constexpr V simd_unchecked_load(I first, iter_difference_t<I> n, simd_flags<Flags...> f = {}); template<class V = see below, contiguous_iterator I, class... Flags> constexpr V simd_unchecked_load(I first, iter_difference_t<I> n, const typename V::mask_type& mask, simd_flags<Flags...> f = {}); template<class V = see below, contiguous_iterator I, sized_sentinel_for<I> S, class... Flags> constexpr V simd_unchecked_load(I first, S last, simd_flags<Flags...> f = {}); template<class V = see below, contiguous_iterator I, sized_sentinel_for<I> S, class... Flags> constexpr V simd_unchecked_load(I first, S last, const typename V::mask_type& mask, simd_flags<Flags...> f = {});
Let
  • mask be V​::​mask_type(true) for the overloads with no mask parameter;
  • R be span<const iter_value_t<I>> for the overloads with no template parameter R;
  • r be R(first, n) for the overloads with an n parameter and R(first, last) for the overloads with a last parameter.
Mandates: If ranges​::​size(r) is a constant expression then ranges​::​size(r)  ≥  V​::​size().
Preconditions:
  • [first, first + n) is a valid range for the overloads with an n parameter.
  • [first, last) is a valid range for the overloads with a last parameter.
  • ranges​::​size(r)  ≥  V​::​size()
Effects: Equivalent to: return simd_partial_load<V>(r, mask, f);
Remarks: The default argument for template parameter V is basic_simd<ranges​::​range_value_t<R>>.
template<class V = see below, ranges::contiguous_range R, class... Flags> requires ranges::sized_range<R> constexpr V simd_partial_load(R&& r, simd_flags<Flags...> f = {}); template<class V = see below, ranges::contiguous_range R, class... Flags> requires ranges::sized_range<R> constexpr V simd_partial_load(R&& r, const typename V::mask_type& mask, simd_flags<Flags...> f = {}); template<class V = see below, contiguous_iterator I, class... Flags> constexpr V simd_partial_load(I first, iter_difference_t<I> n, simd_flags<Flags...> f = {}); template<class V = see below, contiguous_iterator I, class... Flags> constexpr V simd_partial_load(I first, iter_difference_t<I> n, const typename V::mask_type& mask, simd_flags<Flags...> f = {}); template<class V = see below, contiguous_iterator I, sized_sentinel_for<I> S, class... Flags> constexpr V simd_partial_load(I first, S last, simd_flags<Flags...> f = {}); template<class V = see below, contiguous_iterator I, sized_sentinel_for<I> S, class... Flags> constexpr V simd_partial_load(I first, S last, const typename V::mask_type& mask, simd_flags<Flags...> f = {});
Let
  • mask be V​::​mask_type(true) for the overloads with no mask parameter;
  • R be span<const iter_value_t<I>> for the overloads with no template parameter R;
  • r be R(first, n) for the overloads with an n parameter and R(first, last) for the overloads with a last parameter.
Mandates:
  • ranges​::​range_value_t<R> is a vectorizable type,
  • same_as<remove_cvref_t<V>, V> is true,
  • V is an enabled specialization of basic_simd, and
  • if the template parameter pack Flags does not contain convert-flag, then the conversion from ranges​::​range_value_t<R> to V​::​value_type is value-preserving.
Preconditions:
  • [first, first + n) is a valid range for the overloads with an n parameter.
  • [first, last) is a valid range for the overloads with a last parameter.
  • If the template parameter pack Flags contains aligned-flag, ranges​::​data(r) points to storage aligned by simd_alignment_v<V, ranges​::​range_value_t<R>>.
  • If the template parameter pack Flags contains overaligned-flag<N>, ranges​::​data(r) points to storage aligned by N.
Effects: Initializes the element with
mask[i] && i < ranges​::​size(r) ? static_cast<T>(​ranges​::​data(r)[i]) : T() for all i in the range of [0, V​::​size()).
Remarks: The default argument for template parameter V is basic_simd<ranges​::​range_value_t<R>>.
template<class T, class Abi, ranges::contiguous_range R, class... Flags> requires ranges::sized_range<R> && indirectly_writable<ranges::iterator_t<R>, T> constexpr void simd_unchecked_store(const basic_simd<T, Abi>& v, R&& r, simd_flags<Flags...> f = {}); template<class T, class Abi, ranges::contiguous_range R, class... Flags> requires ranges::sized_range<R> && indirectly_writable<ranges::iterator_t<R>, T> constexpr void simd_unchecked_store(const basic_simd<T, Abi>& v, R&& r, const typename basic_simd<T, Abi>::mask_type& mask, simd_flags<Flags...> f = {}); template<class T, class Abi, contiguous_iterator I, class... Flags> requires indirectly_writable<I, T> constexpr void simd_unchecked_store(const basic_simd<T, Abi>& v, I first, iter_difference_t<I> n, simd_flags<Flags...> f = {}); template<class T, class Abi, contiguous_iterator I, class... Flags> requires indirectly_writable<I, T> constexpr void simd_unchecked_store(const basic_simd<T, Abi>& v, I first, iter_difference_t<I> n, const typename basic_simd<T, Abi>::mask_type& mask, simd_flags<Flags...> f = {}); template<class T, class Abi, contiguous_iterator I, sized_sentinel_for<I> S, class... Flags> requires indirectly_writable<I, T> constexpr void simd_unchecked_store(const basic_simd<T, Abi>& v, I first, S last, simd_flags<Flags...> f = {}); template<class T, class Abi, contiguous_iterator I, sized_sentinel_for<I> S, class... Flags> requires indirectly_writable<I, T> constexpr void simd_unchecked_store(const basic_simd<T, Abi>& v, I first, S last, const typename basic_simd<T, Abi>::mask_type& mask, simd_flags<Flags...> f = {});
Let
  • mask be basic_simd<T, Abi>​::​mask_type(true) for the overloads with no mask parameter;
  • R be span<iter_value_t<I>> for the overloads with no template parameter R;
  • r be R(first, n) for the overloads with an n parameter and R(first, last) for the overloads with a last parameter.
Mandates: If ranges​::​size(r) is a constant expression then ranges​::​size(r)  ≥  simd-size-v<T, Abi>.
Preconditions:
  • [first, first + n) is a valid range for the overloads with an n parameter.
  • [first, last) is a valid range for the overloads with a last parameter.
  • ranges​::​size(r)  ≥  simd-size-v<T, Abi>
Effects: Equivalent to: simd_partial_store(v, r, mask, f).
template<class T, class Abi, ranges::contiguous_range R, class... Flags> requires ranges::sized_range<R> && indirectly_writable<ranges::iterator_t<R>, T> constexpr void simd_partial_store(const basic_simd<T, Abi>& v, R&& r, simd_flags<Flags...> f = {}); template<class T, class Abi, ranges::contiguous_range R, class... Flags> requires ranges::sized_range<R> && indirectly_writable<ranges::iterator_t<R>, T> constexpr void simd_partial_store(const basic_simd<T, Abi>& v, R&& r, const typename basic_simd<T, Abi>::mask_type& mask, simd_flags<Flags...> f = {}); template<class T, class Abi, contiguous_iterator I, class... Flags> requires indirectly_writable<I, T> constexpr void simd_partial_store(const basic_simd<T, Abi>& v, I first, iter_difference_t<I> n, simd_flags<Flags...> f = {}); template<class T, class Abi, contiguous_iterator I, class... Flags> requires indirectly_writable<I, T> constexpr void simd_partial_store(const basic_simd<T, Abi>& v, I first, iter_difference_t<I> n, const typename basic_simd<T, Abi>::mask_type& mask, simd_flags<Flags...> f = {}); template<class T, class Abi, contiguous_iterator I, sized_sentinel_for<I> S, class... Flags> requires indirectly_writable<I, T> constexpr void simd_partial_store(const basic_simd<T, Abi>& v, I first, S last, simd_flags<Flags...> f = {}); template<class T, class Abi, contiguous_iterator I, sized_sentinel_for<I> S, class... Flags> requires indirectly_writable<I, T> constexpr void simd_partial_store(const basic_simd<T, Abi>& v, I first, S last, const typename basic_simd<T, Abi>::mask_type& mask, simd_flags<Flags...> f = {});
Let
  • mask be basic_simd<T, Abi>​::​mask_type(true) for the overloads with no mask parameter;
  • R be span<iter_value_t<I>> for the overloads with no template parameter R;
  • r be R(first, n) for the overloads with an n parameter and R(first, last) for the overloads with a last parameter.
Mandates:
  • ranges​::​range_value_t<R> is a vectorizable type, and
  • if the template parameter pack Flags does not contain convert-flag, then the conversion from T to ranges​::​range_value_t<R> is value-preserving.
Preconditions:
  • [first, first + n) is a valid range for the overloads with an n parameter.
  • [first, last) is a valid range for the overloads with a last parameter.
  • If the template parameter pack Flags contains aligned-flag, ranges​::​data(r) points to storage aligned by simd_alignment_v<basic_simd<T, Abi>, ranges​::​range_value_t<R>>.
  • If the template parameter pack Flags contains overaligned-flag<N>, ranges​::​data(r) points to storage aligned by N.
Effects: For all i in the range of [0, basic_simd<T, Abi>​::​size()), if mask[i] && i < ranges​::​​size(r) is true, evaluates ranges​::​data(r)[i] = v[i].

29.10.7.7 basic_simd and basic_simd_mask creation [simd.creation]

template<class T, class Abi> constexpr auto simd_split(const basic_simd<typename T::value_type, Abi>& x) noexcept; template<class T, class Abi> constexpr auto simd_split(const basic_simd_mask<mask-element-size<T>, Abi>& x) noexcept;
Constraints:
  • For the first overload T is an enabled specialization of basic_simd.
    If basic_simd<typename T​::​​value_type, Abi>​::​size() % T​::​size() is not 0 then resize_simd_t<basic_simd<typename T​::​​value_type, Abi>​::​size() % T​::​size(), T> is valid and denotes a type.
  • For the second overload T is an enabled specialization of basic_simd_mask.
    If basic_simd_mask<mask-element-size<T>, Abi>​::​size() % T​::​size() is not 0 then resize_simd_t<​basic_simd_mask<mask-element-size<T>, Abi>​::​size() % T​::​size(), T> is valid and denotes a type.
Let N be x.size() / T​::​size().
Returns:
  • If x.size() % T​::​size() == 0 is true, an array<T, N> with the basic_simd or basic_simd_mask element of the array element initialized to the value of the element in x with index i + j * T​::​size().
  • Otherwise, a tuple of N objects of type T and one object of type resize_simd_t<x.size() % T​::​size(), T>.
    The basic_simd or basic_simd_mask element of the tuple element of type T is initialized to the value of the element in x with index i + j * T​::​size().
    The basic_simd or basic_simd_mask element of the tuple element is initialized to the value of the element in x with index i + N * T​::​size().
template<class T, class... Abis> constexpr simd<T, (basic_simd<T, Abis>::size() + ...)> simd_cat(const basic_simd<T, Abis>&... xs) noexcept; template<size_t Bytes, class... Abis> constexpr basic_simd_mask<Bytes, deduce-abi-t<integer-from<Bytes>, (basic_simd_mask<Bytes, Abis>::size() + ...)>> simd_cat(const basic_simd_mask<Bytes, Abis>&... xs) noexcept;
Constraints:
  • For the first overload simd<T, (basic_simd<T, Abis>​::​size() + ...)> is enabled.
  • For the second overload basic_simd_mask<Bytes, deduce-abi-t<integer-from<Bytes>, (basic_simd_mask<Bytes, Abis>​::​size() + ...)>> is enabled.
Returns: A data-parallel object initialized with the concatenated values in the xs pack of data-parallel objects: The basic_simd/basic_simd_mask element of the parameter in the xs pack is copied to the return value's element with index i + the sum of the width of the first j parameters in the xs pack.

29.10.7.8 Algorithms [simd.alg]

template<class T, class Abi> constexpr basic_simd<T, Abi> min(const basic_simd<T, Abi>& a, const basic_simd<T, Abi>& b) noexcept;
Constraints: T models totally_ordered.
Returns: The result of the element-wise application of min(a[i], b[i]) for all i in the range of [0, basic_simd<T, Abi>​::​size()).
template<class T, class Abi> constexpr basic_simd<T, Abi> max(const basic_simd<T, Abi>& a, const basic_simd<T, Abi>& b) noexcept;
Constraints: T models totally_ordered.
Returns: The result of the element-wise application of max(a[i], b[i]) for all i in the range of [0, basic_simd<T, Abi>​::​size()).
template<class T, class Abi> constexpr pair<basic_simd<T, Abi>, basic_simd<T, Abi>> minmax(const basic_simd<T, Abi>& a, const basic_simd<T, Abi>& b) noexcept;
Effects: Equivalent to: return pair{min(a, b), max(a, b)};
template<class T, class Abi> constexpr basic_simd<T, Abi> clamp( const basic_simd<T, Abi>& v, const basic_simd<T, Abi>& lo, const basic_simd<T, Abi>& hi);
Constraints: T models totally_ordered.
Preconditions: No element in lo shall be greater than the corresponding element in hi.
Returns: The result of element-wise application of clamp(v[i], lo[i], hi[i]) for all i in the range of [0, basic_simd<T, Abi>​::​size()).
template<class T, class U> constexpr auto simd_select(bool c, const T& a, const U& b) -> remove_cvref_t<decltype(c ? a : b)>;
Effects: Equivalent to: return c ? a : b;
template<size_t Bytes, class Abi, class T, class U> constexpr auto simd_select(const basic_simd_mask<Bytes, Abi>& c, const T& a, const U& b) noexcept -> decltype(simd-select-impl(c, a, b));
Effects: Equivalent to: return simd-select-impl(c, a, b); where simd-select-impl is found by argument-dependent lookup ([basic.lookup.argdep]) contrary to [contents].

29.10.7.9 Mathematical functions [simd.math]

template<math-floating-point V> constexpr rebind_simd_t<int, deduced-simd-t<V>> ilogb(const V& x); template<math-floating-point V> constexpr deduced-simd-t<V> ldexp(const V& x, const rebind_simd_t<int, deduced-simd-t<V>>& exp); template<math-floating-point V> constexpr deduced-simd-t<V> scalbn(const V& x, const rebind_simd_t<int, deduced-simd-t<V>>& n); template<math-floating-point V> constexpr deduced-simd-t<V> scalbln(const V& x, const rebind_simd_t<long int, deduced-simd-t<V>>& n); template<signed_integral T, class Abi> constexpr basic_simd<T, Abi> abs(const basic_simd<T, Abi>& j); template<math-floating-point V> constexpr deduced-simd-t<V> abs(const V& j); template<math-floating-point V> constexpr deduced-simd-t<V> fabs(const V& x); template<math-floating-point V> constexpr deduced-simd-t<V> ceil(const V& x); template<math-floating-point V> constexpr deduced-simd-t<V> floor(const V& x); template<math-floating-point V> deduced-simd-t<V> nearbyint(const V& x); template<math-floating-point V> deduced-simd-t<V> rint(const V& x); template<math-floating-point V> rebind_simd_t<long int, deduced-simd-t<V>> lrint(const V& x); template<math-floating-point V> rebind_simd_t<long long int, deduced-simd-t<V>> llrint(const V& x); template<math-floating-point V> constexpr deduced-simd-t<V> round(const V& x); template<math-floating-point V> constexpr rebind_simd_t<long int, deduced-simd-t<V>> lround(const V& x); template<math-floating-point V> constexpr rebind_simd_t<long long int, deduced-simd-t<V>> llround(const V& x); template<class V0, class V1> constexpr math-common-simd-t<V0, V1> fmod(const V0& x, const V1& y); template<math-floating-point V> constexpr deduced-simd-t<V> trunc(const V& x); template<class V0, class V1> constexpr math-common-simd-t<V0, V1> remainder(const V0& x, const V1& y); template<class V0, class V1> constexpr math-common-simd-t<V0, V1> copysign(const V0& x, const V1& y); template<class V0, class V1> constexpr math-common-simd-t<V0, V1> nextafter(const V0& x, const V1& y); template<class V0, class V1> constexpr math-common-simd-t<V0, V1> fdim(const V0& x, const V1& y); template<class V0, class V1> constexpr math-common-simd-t<V0, V1> fmax(const V0& x, const V1& y); template<class V0, class V1> constexpr math-common-simd-t<V0, V1> fmin(const V0& x, const V1& y); template<class V0, class V1, class V2> constexpr math-common-simd-t<V0, V1, V2> fma(const V0& x, const V1& y, const V2& z); template<math-floating-point V> constexpr rebind_simd_t<int, deduced-simd-t<V>> fpclassify(const V& x); template<math-floating-point V> constexpr typename deduced-simd-t<V>::mask_type isfinite(const V& x); template<math-floating-point V> constexpr typename deduced-simd-t<V>::mask_type isinf(const V& x); template<math-floating-point V> constexpr typename deduced-simd-t<V>::mask_type isnan(const V& x); template<math-floating-point V> constexpr typename deduced-simd-t<V>::mask_type isnormal(const V& x); template<math-floating-point V> constexpr typename deduced-simd-t<V>::mask_type signbit(const V& x); template<class V0, class V1> constexpr typename math-common-simd-t<V0, V1>::mask_type isgreater(const V0& x, const V1& y); template<class V0, class V1> constexpr typename math-common-simd-t<V0, V1>::mask_type isgreaterequal(const V0& x, const V1& y); template<class V0, class V1> constexpr typename math-common-simd-t<V0, V1>::mask_type isless(const V0& x, const V1& y); template<class V0, class V1> constexpr typename math-common-simd-t<V0, V1>::mask_type islessequal(const V0& x, const V1& y); template<class V0, class V1> constexpr typename math-common-simd-t<V0, V1>::mask_type islessgreater(const V0& x, const V1& y); template<class V0, class V1> constexpr typename math-common-simd-t<V0, V1>::mask_type isunordered(const V0& x, const V1& y);
Let Ret denote the return type of the specialization of a function template with the name math-func.
Let math-func-simd denote: template<class... Args> Ret math-func-simd(Args... args) { return Ret([&](simd-size-type i) { math-func(make-compatible-simd-t<Ret, Args>(args)[i]...); }); }
Returns: A value ret of type Ret, that is element-wise equal to the result of calling math-func-simd with the arguments of the above functions.
If in an invocation of a scalar overload of math-func for index i in math-func-simd a domain, pole, or range error would occur, the value of ret[i] is unspecified.
Remarks: It is unspecified whether errno ([errno]) is accessed.
template<math-floating-point V> constexpr deduced-simd-t<V> acos(const V& x); template<math-floating-point V> constexpr deduced-simd-t<V> asin(const V& x); template<math-floating-point V> constexpr deduced-simd-t<V> atan(const V& x); template<class V0, class V1> constexpr math-common-simd-t<V0, V1> atan2(const V0& y, const V1& x); template<math-floating-point V> constexpr deduced-simd-t<V> cos(const V& x); template<math-floating-point V> constexpr deduced-simd-t<V> sin(const V& x); template<math-floating-point V> constexpr deduced-simd-t<V> tan(const V& x); template<math-floating-point V> constexpr deduced-simd-t<V> acosh(const V& x); template<math-floating-point V> constexpr deduced-simd-t<V> asinh(const V& x); template<math-floating-point V> constexpr deduced-simd-t<V> atanh(const V& x); template<math-floating-point V> constexpr deduced-simd-t<V> cosh(const V& x); template<math-floating-point V> constexpr deduced-simd-t<V> sinh(const V& x); template<math-floating-point V> constexpr deduced-simd-t<V> tanh(const V& x); template<math-floating-point V> constexpr deduced-simd-t<V> exp(const V& x); template<math-floating-point V> constexpr deduced-simd-t<V> exp2(const V& x); template<math-floating-point V> constexpr deduced-simd-t<V> expm1(const V& x); template<math-floating-point V> constexpr deduced-simd-t<V> log(const V& x); template<math-floating-point V> constexpr deduced-simd-t<V> log10(const V& x); template<math-floating-point V> constexpr deduced-simd-t<V> log1p(const V& x); template<math-floating-point V> constexpr deduced-simd-t<V> log2(const V& x); template<math-floating-point V> constexpr deduced-simd-t<V> logb(const V& x); template<math-floating-point V> constexpr deduced-simd-t<V> cbrt(const V& x); template<class V0, class V1> constexpr math-common-simd-t<V0, V1> hypot(const V0& x, const V1& y); template<class V0, class V1, class V2> constexpr math-common-simd-t<V0, V1, V2> hypot(const V0& x, const V1& y, const V2& z); template<class V0, class V1> constexpr math-common-simd-t<V0, V1> pow(const V0& x, const V1& y); template<math-floating-point V> constexpr deduced-simd-t<V> sqrt(const V& x); template<math-floating-point V> constexpr deduced-simd-t<V> erf(const V& x); template<math-floating-point V> constexpr deduced-simd-t<V> erfc(const V& x); template<math-floating-point V> constexpr deduced-simd-t<V> lgamma(const V& x); template<math-floating-point V> constexpr deduced-simd-t<V> tgamma(const V& x); template<class V0, class V1, class V2> constexpr math-common-simd-t<V0, V1, V2> lerp(const V0& a, const V1& b, const V2& t) noexcept; template<math-floating-point V> deduced-simd-t<V> assoc_laguerre(const rebind_simd_t<unsigned, deduced-simd-t<V>>& n, const rebind_simd_t<unsigned, deduced-simd-t<V>>& m, const V& x); template<math-floating-point V> deduced-simd-t<V> assoc_legendre(const rebind_simd_t<unsigned, deduced-simd-t<V>>& l, const rebind_simd_t<unsigned, deduced-simd-t<V>>& m, const V& x); template<class V0, class V1> math-common-simd-t<V0, V1> beta(const V0& x, const V1& y); template<math-floating-point V> deduced-simd-t<V> comp_ellint_1(const V& k); template<math-floating-point V> deduced-simd-t<V> comp_ellint_2(const V& k); template<class V0, class V1> math-common-simd-t<V0, V1> comp_ellint_3(const V0& k, const V1& nu); template<class V0, class V1> math-common-simd-t<V0, V1> cyl_bessel_i(const V0& nu, const V1& x); template<class V0, class V1> math-common-simd-t<V0, V1> cyl_bessel_j(const V0& nu, const V1& x); template<class V0, class V1> math-common-simd-t<V0, V1> cyl_bessel_k(const V0& nu, const V1& x); template<class V0, class V1> math-common-simd-t<V0, V1> cyl_neumann(const V0& nu, const V1& x); template<class V0, class V1> math-common-simd-t<V0, V1> ellint_1(const V0& k, const V1& phi); template<class V0, class V1> math-common-simd-t<V0, V1> ellint_2(const V0& k, const V1& phi); template<class V0, class V1, class V2> math-common-simd-t<V0, V1, V2> ellint_3(const V0& k, const V1& nu, const V2& phi); template<math-floating-point V> deduced-simd-t<V> expint(const V& x); template<math-floating-point V> deduced-simd-t<V> hermite(const rebind_simd_t<unsigned, deduced-simd-t<V>>& n, const V& x); template<math-floating-point V> deduced-simd-t<V> laguerre(const rebind_simd_t<unsigned, deduced-simd-t<V>>& n, const V& x); template<math-floating-point V> deduced-simd-t<V> legendre(const rebind_simd_t<unsigned, deduced-simd-t<V>>& l, const V& x); template<math-floating-point V> deduced-simd-t<V> riemann_zeta(const V& x); template<math-floating-point V> deduced-simd-t<V> sph_bessel(const rebind_simd_t<unsigned, deduced-simd-t<V>>& n, const V& x); template<math-floating-point V> deduced-simd-t<V> sph_legendre(const rebind_simd_t<unsigned, deduced-simd-t<V>>& l, const rebind_simd_t<unsigned, deduced-simd-t<V>>& m, const V& theta); template<math-floating-point V> deduced-simd-t<V> sph_neumann(const rebind_simd_t<unsigned, deduced-simd-t<V>>& n, const V& x);
Let Ret denote the return type of the specialization of a function template with the name math-func.
Let math-func-simd denote: template<class... Args> Ret math-func-simd(Args... args) { return Ret([&](simd-size-type i) { math-func(make-compatible-simd-t<Ret, Args>(args)[i]...); }); }
Returns: A value ret of type Ret, that is element-wise approximately equal to the result of calling math-func-simd with the arguments of the above functions.
If in an invocation of a scalar overload of math-func for index i in math-func-simd a domain, pole, or range error would occur, the value of ret[i] is unspecified.
Remarks: It is unspecified whether errno ([errno]) is accessed.
template<math-floating-point V> constexpr deduced-simd-t<V> frexp(const V& value, rebind_simd_t<int, deduced-simd-t<V>>* exp);
Let Ret be deduced-simd-t<V>.
Let frexp-simd denote: template<class V> pair<Ret, rebind_simd_t<int, Ret>> frexp-simd(const V& x) { int r1[Ret::size()]; Ret r0([&](simd-size-type i) { frexp(make-compatible-simd-t<Ret, V>(x)[i], &r1[i]); }); return {r0, rebind_simd_t<int, Ret>(r1)}; }
Let ret be a value of type pair<Ret, rebind_simd_t<int, Ret>> that is the same value as the result of calling frexp-simd(x).
Effects: Sets *exp to ret.second.
Returns: ret.first.
template<class V0, class V1> constexpr math-common-simd-t<V0, V1> remquo(const V0& x, const V1& y, rebind_simd_t<int, math-common-simd-t<V0, V1>>* quo);
Let Ret be math-common-simd-t<V0, V1>.
Let remquo-simd denote: template<class V0, class V1> pair<Ret, rebind_simd_t<int, Ret>> remquo-simd(const V0& x, const V1& y) { int r1[Ret::size()]; Ret r0([&](simd-size-type i) { remquo(make-compatible-simd-t<Ret, V0>(x)[i], make-compatible-simd-t<Ret, V1>(y)[i], &r1[i]); }); return {r0, rebind_simd_t<int, Ret>(r1)}; }
Let ret be a value of type pair<Ret, rebind_simd_t<int, Ret>> that is the same value as the result of calling remquo-simd(x, y).
If in an invocation of a scalar overload of remquo for index i in remquo-simd a domain, pole, or range error would occur, the value of ret[i] is unspecified.
Effects: Sets *quo to ret.second.
Returns: ret.first.
Remarks: It is unspecified whether errno ([errno]) is accessed.
template<class T, class Abi> constexpr basic_simd<T, Abi> modf(const type_identity_t<basic_simd<T, Abi>>& value, basic_simd<T, Abi>* iptr);
Let V be basic_simd<T, Abi>.
Let modf-simd denote: pair<V, V> modf-simd(const V& x) { T r1[Ret::size()]; V r0([&](simd-size-type i) { modf(V(x)[i], &r1[i]); }); return {r0, V(r1)}; }
Let ret be a value of type pair<V, V> that is the same value as the result of calling modf-simd(value).
Effects: Sets *iptr to ret.second.
Returns: ret.first.

29.10.8 Class template basic_simd_mask [simd.mask.class]

29.10.8.1 Class template basic_simd_mask overview [simd.mask.overview]

namespace std { template<size_t Bytes, class Abi> class basic_simd_mask { public: using value_type = bool; using abi_type = Abi; static constexpr integral_constant<simd-size-type, simd-size-v<integer-from<Bytes>, Abi>> size {}; constexpr basic_simd_mask() noexcept = default; // [simd.mask.ctor], basic_simd_mask constructors constexpr explicit basic_simd_mask(value_type) noexcept; template<size_t UBytes, class UAbi> constexpr explicit basic_simd_mask(const basic_simd_mask<UBytes, UAbi>&) noexcept; template<class G> constexpr explicit basic_simd_mask(G&& gen) noexcept; // [simd.mask.subscr], basic_simd_mask subscript operators constexpr value_type operator[](simd-size-type) const; // [simd.mask.unary], basic_simd_mask unary operators constexpr basic_simd_mask operator!() const noexcept; constexpr basic_simd<integer-from<Bytes>, Abi> operator+() const noexcept; constexpr basic_simd<integer-from<Bytes>, Abi> operator-() const noexcept; constexpr basic_simd<integer-from<Bytes>, Abi> operator~() const noexcept; // [simd.mask.conv], basic_simd_mask conversion operators template<class U, class A> constexpr explicit(sizeof(U) != Bytes) operator basic_simd<U, A>() const noexcept; // [simd.mask.binary], basic_simd_mask binary operators friend constexpr basic_simd_mask operator&&(const basic_simd_mask&, const basic_simd_mask&) noexcept; friend constexpr basic_simd_mask operator||(const basic_simd_mask&, const basic_simd_mask&) noexcept; friend constexpr basic_simd_mask operator&(const basic_simd_mask&, const basic_simd_mask&) noexcept; friend constexpr basic_simd_mask operator|(const basic_simd_mask&, const basic_simd_mask&) noexcept; friend constexpr basic_simd_mask operator^(const basic_simd_mask&, const basic_simd_mask&) noexcept; // [simd.mask.cassign], basic_simd_mask compound assignment friend constexpr basic_simd_mask& operator&=(basic_simd_mask&, const basic_simd_mask&) noexcept; friend constexpr basic_simd_mask& operator|=(basic_simd_mask&, const basic_simd_mask&) noexcept; friend constexpr basic_simd_mask& operator^=(basic_simd_mask&, const basic_simd_mask&) noexcept; // [simd.mask.comparison], basic_simd_mask comparisons friend constexpr basic_simd_mask operator==(const basic_simd_mask&, const basic_simd_mask&) noexcept; friend constexpr basic_simd_mask operator!=(const basic_simd_mask&, const basic_simd_mask&) noexcept; friend constexpr basic_simd_mask operator>=(const basic_simd_mask&, const basic_simd_mask&) noexcept; friend constexpr basic_simd_mask operator<=(const basic_simd_mask&, const basic_simd_mask&) noexcept; friend constexpr basic_simd_mask operator>(const basic_simd_mask&, const basic_simd_mask&) noexcept; friend constexpr basic_simd_mask operator<(const basic_simd_mask&, const basic_simd_mask&) noexcept; // [simd.mask.cond], basic_simd_mask exposition only conditional operators friend constexpr basic_simd_mask simd-select-impl( // exposition only const basic_simd_mask&, const basic_simd_mask&, const basic_simd_mask&) noexcept; friend constexpr basic_simd_mask simd-select-impl( // exposition only const basic_simd_mask&, same_as<bool> auto, same_as<bool> auto) noexcept; template<class T0, class T1> friend constexpr simd<see below, size()> simd-select-impl(const basic_simd_mask&, const T0&, const T1&) noexcept; // exposition only }; }
Every specialization of basic_simd_mask is a complete type.
The specialization of basic_simd_mask<Bytes, Abi> is:
  • disabled, if there is no vectorizable type T such that Bytes is equal to sizeof(T),
  • otherwise, enabled, if there exists a vectorizable type T and a value N in the range [1, 64] such that Bytes is equal to sizeof(T) and Abi is deduce-abi-t<T, N>,
  • otherwise, it is implementation-defined if such a specialization is enabled.
If basic_simd_mask<Bytes, Abi> is disabled, the specialization has a deleted default constructor, deleted destructor, deleted copy constructor, and deleted copy assignment.
In addition only the value_type and abi_type members are present.
If basic_simd_mask<Bytes, Abi> is enabled, basic_simd_mask<Bytes, Abi> is trivially copyable.
Recommended practice: Implementations should support explicit conversions between specializations of basic_simd_mask and appropriate implementation-defined types.
[Note 1: 
Appropriate types are non-standard vector types which are available in the implementation.
— end note]

29.10.8.2 basic_simd_mask constructors [simd.mask.ctor]

constexpr explicit basic_simd_mask(value_type x) noexcept;
Effects: Initializes each element with x.
template<size_t UBytes, class UAbi> constexpr explicit basic_simd_mask(const basic_simd_mask<UBytes, UAbi>& x) noexcept;
Constraints: basic_simd_mask<UBytes, UAbi>​::​size() == size() is true.
Effects: Initializes the element with x[i] for all i in the range of [0, size()).
template<class G> constexpr explicit basic_simd_mask(G&& gen) noexcept;
Constraints: The expression gen(integral_constant<simd-size-type, i>()) is well-formed and its type is bool for all i in the range of [0, size()).
Effects: Initializes the element with gen(integral_constant<simd-size-type, i>()) for all i in the range of [0, size()).
Remarks: The calls to gen are unsequenced with respect to each other.
Vectorization-unsafe ([algorithms.parallel.defns]) standard library functions may not be invoked by gen.
gen is invoked exactly once for each i.

29.10.8.3 basic_simd_mask subscript operator [simd.mask.subscr]

constexpr value_type operator[](simd-size-type i) const;
Preconditions: i >= 0 && i < size() is true.
Returns: The value of the element.
Throws: Nothing.

29.10.8.4 basic_simd_mask unary operators [simd.mask.unary]

constexpr basic_simd_mask operator!() const noexcept; constexpr basic_simd<integer-from<Bytes>, Abi> operator+() const noexcept; constexpr basic_simd<integer-from<Bytes>, Abi> operator-() const noexcept; constexpr basic_simd<integer-from<Bytes>, Abi> operator~() const noexcept;
Let op be the operator.
Returns: A data-parallel object where the element is initialized to the results of applying op to operator[](i) for all i in the range of [0, size()).

29.10.8.5 basic_simd_mask conversion operators [simd.mask.conv]

template<class U, class A> constexpr explicit(sizeof(U) != Bytes) operator basic_simd<U, A>() const noexcept;
Constraints: simd-size-v<U, A> == simd-size-v<T, Abi>.
Returns: A data-parallel object where the element is initialized to static_cast<U>(operator[](i)).

29.10.9 Non-member operations [simd.mask.nonmembers]

29.10.9.1 basic_simd_mask binary operators [simd.mask.binary]

friend constexpr basic_simd_mask operator&&(const basic_simd_mask& lhs, const basic_simd_mask& rhs) noexcept; friend constexpr basic_simd_mask operator||(const basic_simd_mask& lhs, const basic_simd_mask& rhs) noexcept; friend constexpr basic_simd_mask operator& (const basic_simd_mask& lhs, const basic_simd_mask& rhs) noexcept; friend constexpr basic_simd_mask operator| (const basic_simd_mask& lhs, const basic_simd_mask& rhs) noexcept; friend constexpr basic_simd_mask operator^ (const basic_simd_mask& lhs, const basic_simd_mask& rhs) noexcept;
Let op be the operator.
Returns: A basic_simd_mask object initialized with the results of applying op to lhs and rhs as a binary element-wise operation.

29.10.9.2 basic_simd_mask compound assignment [simd.mask.cassign]

friend constexpr basic_simd_mask& operator&=(basic_simd_mask& lhs, const basic_simd_mask& rhs) noexcept; friend constexpr basic_simd_mask& operator|=(basic_simd_mask& lhs, const basic_simd_mask& rhs) noexcept; friend constexpr basic_simd_mask& operator^=(basic_simd_mask& lhs, const basic_simd_mask& rhs) noexcept;
Let op be the operator.
Effects: These operators apply op to lhs and rhs as a binary element-wise operation.
Returns: lhs.

29.10.9.3 basic_simd_mask comparisons [simd.mask.comparison]

friend constexpr basic_simd_mask operator==(const basic_simd_mask&, const basic_simd_mask&) noexcept; friend constexpr basic_simd_mask operator!=(const basic_simd_mask&, const basic_simd_mask&) noexcept; friend constexpr basic_simd_mask operator>=(const basic_simd_mask&, const basic_simd_mask&) noexcept; friend constexpr basic_simd_mask operator<=(const basic_simd_mask&, const basic_simd_mask&) noexcept; friend constexpr basic_simd_mask operator>(const basic_simd_mask&, const basic_simd_mask&) noexcept; friend constexpr basic_simd_mask operator<(const basic_simd_mask&, const basic_simd_mask&) noexcept;
Let op be the operator.
Returns: A basic_simd_mask object initialized with the results of applying op to lhs and rhs as a binary element-wise operation.

29.10.9.4 basic_simd_mask exposition only conditional operators [simd.mask.cond]

friend constexpr basic_simd_mask simd-select-impl( const basic_simd_mask& mask, const basic_simd_mask& a, const basic_simd_mask& b) noexcept;
Returns: A basic_simd_mask object where the element equals mask[i] ? a[i] : b[i] for all i in the range of [0, size()).
friend constexpr basic_simd_mask simd-select-impl(const basic_simd_mask& mask, same_as<bool> auto a, same_as<bool> auto b) noexcept;
Returns: A basic_simd_mask object where the element equals mask[i] ? a : b for all i in the range of [0, size()).
template<class T0, class T1> friend constexpr simd<see below, size()> simd-select-impl(const basic_simd_mask& mask, const T0& a, const T1& b) noexcept;
Constraints:
  • same_as<T0, T1> is true,
  • T0 is a vectorizable type, and
  • sizeof(T0) == Bytes.
Returns: A simd<T0, size()> object where the element equals mask[i] ? a : b for all i in the range of [0, size()).

29.10.9.5 basic_simd_mask reductions [simd.mask.reductions]

template<size_t Bytes, class Abi> constexpr bool all_of(const basic_simd_mask<Bytes, Abi>& k) noexcept;
Returns: true if all boolean elements in k are true, otherwise false.
template<size_t Bytes, class Abi> constexpr bool any_of(const basic_simd_mask<Bytes, Abi>& k) noexcept;
Returns: true if at least one boolean element in k is true, otherwise false.
template<size_t Bytes, class Abi> constexpr bool none_of(const basic_simd_mask<Bytes, Abi>& k) noexcept;
Returns: !any_of(k).
template<size_t Bytes, class Abi> constexpr simd-size-type reduce_count(const basic_simd_mask<Bytes, Abi>& k) noexcept;
Returns: The number of boolean elements in k that are true.
template<size_t Bytes, class Abi> constexpr simd-size-type reduce_min_index(const basic_simd_mask<Bytes, Abi>& k);
Preconditions: any_of(k) is true.
Returns: The lowest element index i where k[i] is true.
template<size_t Bytes, class Abi> constexpr simd-size-type reduce_max_index(const basic_simd_mask<Bytes, Abi>& k);
Preconditions: any_of(k) is true.
Returns: The greatest element index i where k[i] is true.
constexpr bool all_of(same_as<bool> auto x) noexcept; constexpr bool any_of(same_as<bool> auto x) noexcept; constexpr simd-size-type reduce_count(same_as<bool> auto x) noexcept;
Returns: x.
constexpr bool none_of(same_as<bool> auto x) noexcept;
Returns: !x.
constexpr simd-size-type reduce_min_index(same_as<bool> auto x); constexpr simd-size-type reduce_max_index(same_as<bool> auto x);
Preconditions: x is true.
Returns: 0.