Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-11-07 10:36:58

0001 /***************************************************************************
0002  * Copyright (c) Johan Mabille, Sylvain Corlay, Wolf Vollprecht and         *
0003  * Martin Renou                                                             *
0004  * Copyright (c) QuantStack                                                 *
0005  * Copyright (c) Serge Guelton                                              *
0006  *                                                                          *
0007  * Distributed under the terms of the BSD 3-Clause License.                 *
0008  *                                                                          *
0009  * The full license is in the file LICENSE, distributed with this software. *
0010  ****************************************************************************/
0011 
0012 #ifndef XSIMD_COMMON_LOGICAL_HPP
0013 #define XSIMD_COMMON_LOGICAL_HPP
0014 
0015 #include "./xsimd_common_bit.hpp"
0016 #include "./xsimd_common_details.hpp"
0017 
0018 #include <climits>
0019 
0020 namespace xsimd
0021 {
0022 
0023     namespace kernel
0024     {
0025 
0026         using namespace types;
0027 
0028         // count
0029         template <class A, class T>
0030         XSIMD_INLINE size_t count(batch_bool<T, A> const& self, requires_arch<common>) noexcept
0031         {
0032             return xsimd::detail::popcount(self.mask());
0033         }
0034 
0035         template <class A, class T>
0036         XSIMD_INLINE size_t countl_zero(batch_bool<T, A> const& self, requires_arch<common>) noexcept
0037         {
0038             constexpr size_t unused_bits = 64 - batch_bool<T, A>::size;
0039             constexpr uint64_t lower_mask = batch_bool<T, A>::size < 64 ? ((uint64_t)1 << (batch_bool<T, A>::size % 64)) - 1 : (uint64_t)-1;
0040             return xsimd::detail::countl_zero(self.mask() & lower_mask) - unused_bits;
0041         }
0042 
0043         template <class A, class T>
0044         XSIMD_INLINE size_t countl_one(batch_bool<T, A> const& self, requires_arch<common>) noexcept
0045         {
0046             constexpr size_t unused_bits = 64 - batch_bool<T, A>::size;
0047             constexpr uint64_t upper_mask = batch_bool<T, A>::size < 64 ? ~(((uint64_t)1 << (batch_bool<T, A>::size % 64)) - 1) : (uint64_t)0;
0048             return xsimd::detail::countl_one(self.mask() | upper_mask) - unused_bits;
0049         }
0050 
0051         template <class A, class T>
0052         XSIMD_INLINE size_t countr_zero(batch_bool<T, A> const& self, requires_arch<common>) noexcept
0053         {
0054             constexpr uint64_t stop = batch_bool<T, A>::size < 64 ? (uint64_t)1 << (batch_bool<T, A>::size % 64) : 0;
0055             return xsimd::detail::countr_zero(self.mask() | stop);
0056         }
0057 
0058         template <class A, class T>
0059         XSIMD_INLINE size_t countr_one(batch_bool<T, A> const& self, requires_arch<common>) noexcept
0060         {
0061             constexpr uint64_t stop = batch_bool<T, A>::size < 64 ? ~((uint64_t)1 << (batch_bool<T, A>::size % 64)) : (uint64_t)-1;
0062             return xsimd::detail::countr_one(self.mask() & stop);
0063         }
0064 
0065         // from  mask
0066         template <class A, class T>
0067         XSIMD_INLINE batch_bool<T, A> from_mask(batch_bool<T, A> const&, uint64_t mask, requires_arch<common>) noexcept
0068         {
0069             alignas(A::alignment()) bool buffer[batch_bool<T, A>::size];
0070             // This is inefficient and should never be called.
0071             for (size_t i = 0; i < batch_bool<T, A>::size; ++i)
0072                 buffer[i] = mask & (1ull << i);
0073             return batch_bool<T, A>::load_aligned(buffer);
0074         }
0075 
0076         // ge
0077         template <class A, class T>
0078         XSIMD_INLINE batch_bool<T, A> ge(batch<T, A> const& self, batch<T, A> const& other, requires_arch<common>) noexcept
0079         {
0080             return other <= self;
0081         }
0082 
0083         // gt
0084         template <class A, class T>
0085         XSIMD_INLINE batch_bool<T, A> gt(batch<T, A> const& self, batch<T, A> const& other, requires_arch<common>) noexcept
0086         {
0087             return other < self;
0088         }
0089 
0090         // is_even
0091         template <class A, class T>
0092         XSIMD_INLINE batch_bool<T, A> is_even(batch<T, A> const& self, requires_arch<common>) noexcept
0093         {
0094             return is_flint(self * T(0.5));
0095         }
0096 
0097         // is_flint
0098         template <class A, class T>
0099         XSIMD_INLINE batch_bool<T, A> is_flint(batch<T, A> const& self, requires_arch<common>) noexcept
0100         {
0101             auto frac = select(isnan(self - self), constants::nan<batch<T, A>>(), self - trunc(self));
0102             return frac == T(0.);
0103         }
0104 
0105         // is_odd
0106         template <class A, class T>
0107         XSIMD_INLINE batch_bool<T, A> is_odd(batch<T, A> const& self, requires_arch<common>) noexcept
0108         {
0109             return is_even(self - T(1.));
0110         }
0111 
0112         // isinf
0113         template <class A, class T, class = std::enable_if_t<std::is_integral<T>::value>>
0114         XSIMD_INLINE batch_bool<T, A> isinf(batch<T, A> const&, requires_arch<common>) noexcept
0115         {
0116             return batch_bool<T, A>(false);
0117         }
0118         template <class A>
0119         XSIMD_INLINE batch_bool<float, A> isinf(batch<float, A> const& self, requires_arch<common>) noexcept
0120         {
0121 #ifdef __FAST_MATH__
0122             (void)self;
0123             return { false };
0124 #else
0125             return abs(self) == std::numeric_limits<float>::infinity();
0126 #endif
0127         }
0128         template <class A>
0129         XSIMD_INLINE batch_bool<double, A> isinf(batch<double, A> const& self, requires_arch<common>) noexcept
0130         {
0131 #ifdef __FAST_MATH__
0132             (void)self;
0133             return { false };
0134 #else
0135             return abs(self) == std::numeric_limits<double>::infinity();
0136 #endif
0137         }
0138 
0139         // isfinite
0140         template <class A, class T, class = std::enable_if_t<std::is_integral<T>::value>>
0141         XSIMD_INLINE batch_bool<T, A> isfinite(batch<T, A> const&, requires_arch<common>) noexcept
0142         {
0143             return batch_bool<T, A>(true);
0144         }
0145         template <class A>
0146         XSIMD_INLINE batch_bool<float, A> isfinite(batch<float, A> const& self, requires_arch<common>) noexcept
0147         {
0148             return (self - self) == 0.f;
0149         }
0150         template <class A>
0151         XSIMD_INLINE batch_bool<double, A> isfinite(batch<double, A> const& self, requires_arch<common>) noexcept
0152         {
0153             return (self - self) == 0.;
0154         }
0155 
0156         // isnan
0157         template <class A, class T, class = std::enable_if_t<std::is_integral<T>::value>>
0158         XSIMD_INLINE batch_bool<T, A> isnan(batch<T, A> const&, requires_arch<common>) noexcept
0159         {
0160             return batch_bool<T, A>(false);
0161         }
0162 
0163         // le
0164         template <class A, class T, class = std::enable_if_t<std::is_integral<T>::value>>
0165         XSIMD_INLINE batch_bool<T, A> le(batch<T, A> const& self, batch<T, A> const& other, requires_arch<common>) noexcept
0166         {
0167             return (self < other) || (self == other);
0168         }
0169 
0170         // neq
0171         template <class A, class T>
0172         XSIMD_INLINE batch_bool<T, A> neq(batch<T, A> const& self, batch<T, A> const& other, requires_arch<common>) noexcept
0173         {
0174             return !(other == self);
0175         }
0176 
0177         // logical_and
0178         template <class A, class T>
0179         XSIMD_INLINE batch<T, A> logical_and(batch<T, A> const& self, batch<T, A> const& other, requires_arch<common>) noexcept
0180         {
0181             return detail::apply([](T x, T y) noexcept
0182                                  { return x && y; },
0183                                  self, other);
0184         }
0185 
0186         // logical_or
0187         template <class A, class T>
0188         XSIMD_INLINE batch<T, A> logical_or(batch<T, A> const& self, batch<T, A> const& other, requires_arch<common>) noexcept
0189         {
0190             return detail::apply([](T x, T y) noexcept
0191                                  { return x || y; },
0192                                  self, other);
0193         }
0194 
0195         // mask
0196         template <class A, class T>
0197         XSIMD_INLINE uint64_t mask(batch_bool<T, A> const& self, requires_arch<common>) noexcept
0198         {
0199             alignas(A::alignment()) bool buffer[batch_bool<T, A>::size];
0200             self.store_aligned(buffer);
0201             // This is inefficient and should never be called.
0202             uint64_t res = 0;
0203             for (size_t i = 0; i < batch_bool<T, A>::size; ++i)
0204                 if (buffer[i])
0205                     res |= 1ul << i;
0206             return res;
0207         }
0208 
0209         // select
0210         namespace detail
0211         {
0212             template <typename T, typename A>
0213             using is_batch_bool_register_same = std::is_same<typename batch_bool<T, A>::register_type, typename batch<T, A>::register_type>;
0214         }
0215 
0216         template <class A, class T, std::enable_if_t<detail::is_batch_bool_register_same<T, A>::value, int> = 3>
0217         XSIMD_INLINE batch_bool<T, A> select(batch_bool<T, A> const& cond, batch_bool<T, A> const& true_br, batch_bool<T, A> const& false_br, requires_arch<common>)
0218         {
0219             using register_type = typename batch_bool<T, A>::register_type;
0220             // Do not cast, but rather reinterpret the masks as batches.
0221             const auto true_v = batch<T, A> { static_cast<register_type>(true_br) };
0222             const auto false_v = batch<T, A> { static_cast<register_type>(false_br) };
0223             return batch_bool<T, A> { select(cond, true_v, false_v) };
0224         }
0225 
0226         template <class A, class T, std::enable_if_t<!detail::is_batch_bool_register_same<T, A>::value, int> = 3>
0227         XSIMD_INLINE batch_bool<T, A> select(batch_bool<T, A> const& cond, batch_bool<T, A> const& true_br, batch_bool<T, A> const& false_br, requires_arch<common>)
0228         {
0229             return (true_br & cond) | (bitwise_andnot(false_br, cond));
0230         }
0231 
0232         template <class A, class T, bool... Values>
0233         XSIMD_INLINE batch_bool<T, A> select(batch_bool_constant<T, A, Values...> const& cond, batch_bool<T, A> const& true_br, batch_bool<T, A> const& false_br, requires_arch<common>)
0234         {
0235             return (true_br & cond) | (false_br & ~cond);
0236         }
0237     }
0238 }
0239 
0240 #endif