1 | /*************************************************************************** |
2 | * Copyright (c) Johan Mabille, Sylvain Corlay, Wolf Vollprecht and * |
3 | * Martin Renou * |
4 | * Copyright (c) QuantStack * |
5 | * Copyright (c) Serge Guelton * |
6 | * * |
7 | * Distributed under the terms of the BSD 3-Clause License. * |
8 | * * |
9 | * The full license is in the file LICENSE, distributed with this software. * |
10 | ****************************************************************************/ |
11 | |
12 | #ifndef XSIMD_GENERIC_LOGICAL_HPP |
13 | #define XSIMD_GENERIC_LOGICAL_HPP |
14 | |
15 | #include "./xsimd_generic_details.hpp" |
16 | |
17 | namespace xsimd |
18 | { |
19 | |
20 | namespace kernel |
21 | { |
22 | |
23 | using namespace types; |
24 | |
25 | // from mask |
26 | template <class A, class T> |
27 | inline batch_bool<T, A> from_mask(batch_bool<T, A> const&, uint64_t mask, requires_arch<generic>) noexcept |
28 | { |
29 | alignas(A::alignment()) bool buffer[batch_bool<T, A>::size]; |
30 | // This is inefficient but should never be called. It's just a |
31 | // temporary implementation until arm support is added. |
32 | for (size_t i = 0; i < batch_bool<T, A>::size; ++i) |
33 | buffer[i] = mask & (1ull << i); |
34 | return batch_bool<T, A>::load_aligned(buffer); |
35 | } |
36 | |
37 | // ge |
38 | template <class A, class T> |
39 | inline batch_bool<T, A> ge(batch<T, A> const& self, batch<T, A> const& other, requires_arch<generic>) noexcept |
40 | { |
41 | return other <= self; |
42 | } |
43 | |
44 | // gt |
45 | template <class A, class T> |
46 | inline batch_bool<T, A> gt(batch<T, A> const& self, batch<T, A> const& other, requires_arch<generic>) noexcept |
47 | { |
48 | return other < self; |
49 | } |
50 | |
51 | // is_even |
52 | template <class A, class T> |
53 | inline batch_bool<T, A> is_even(batch<T, A> const& self, requires_arch<generic>) noexcept |
54 | { |
55 | return is_flint(self * T(0.5)); |
56 | } |
57 | |
58 | // is_flint |
59 | template <class A, class T> |
60 | inline batch_bool<T, A> is_flint(batch<T, A> const& self, requires_arch<generic>) noexcept |
61 | { |
62 | auto frac = select(isnan(self - self), constants::nan<batch<T, A>>(), self - trunc(self)); |
63 | return frac == T(0.); |
64 | } |
65 | |
66 | // is_odd |
67 | template <class A, class T> |
68 | inline batch_bool<T, A> is_odd(batch<T, A> const& self, requires_arch<generic>) noexcept |
69 | { |
70 | return is_even(self - T(1.)); |
71 | } |
72 | |
73 | // isinf |
74 | template <class A, class T, class = typename std::enable_if<std::is_integral<T>::value, void>::type> |
75 | inline batch_bool<T, A> isinf(batch<T, A> const&, requires_arch<generic>) noexcept |
76 | { |
77 | return batch_bool<T, A>(false); |
78 | } |
79 | template <class A> |
80 | inline batch_bool<float, A> isinf(batch<float, A> const& self, requires_arch<generic>) noexcept |
81 | { |
82 | return abs(self) == std::numeric_limits<float>::infinity(); |
83 | } |
84 | template <class A> |
85 | inline batch_bool<double, A> isinf(batch<double, A> const& self, requires_arch<generic>) noexcept |
86 | { |
87 | return abs(self) == std::numeric_limits<double>::infinity(); |
88 | } |
89 | |
90 | // isfinite |
91 | template <class A, class T, class = typename std::enable_if<std::is_integral<T>::value, void>::type> |
92 | inline batch_bool<T, A> isfinite(batch<T, A> const&, requires_arch<generic>) noexcept |
93 | { |
94 | return batch_bool<T, A>(true); |
95 | } |
96 | template <class A> |
97 | inline batch_bool<float, A> isfinite(batch<float, A> const& self, requires_arch<generic>) noexcept |
98 | { |
99 | return (self - self) == 0.f; |
100 | } |
101 | template <class A> |
102 | inline batch_bool<double, A> isfinite(batch<double, A> const& self, requires_arch<generic>) noexcept |
103 | { |
104 | return (self - self) == 0.; |
105 | } |
106 | |
107 | // isnan |
108 | template <class A, class T, class = typename std::enable_if<std::is_integral<T>::value, void>::type> |
109 | inline batch_bool<T, A> isnan(batch<T, A> const&, requires_arch<generic>) noexcept |
110 | { |
111 | return batch_bool<T, A>(false); |
112 | } |
113 | |
114 | // le |
115 | template <class A, class T, class = typename std::enable_if<std::is_integral<T>::value, void>::type> |
116 | inline batch_bool<T, A> le(batch<T, A> const& self, batch<T, A> const& other, requires_arch<generic>) noexcept |
117 | { |
118 | return (self < other) || (self == other); |
119 | } |
120 | |
121 | // neq |
122 | template <class A, class T> |
123 | inline batch_bool<T, A> neq(batch<T, A> const& self, batch<T, A> const& other, requires_arch<generic>) noexcept |
124 | { |
125 | return !(other == self); |
126 | } |
127 | |
128 | // logical_and |
129 | template <class A, class T> |
130 | inline batch<T, A> logical_and(batch<T, A> const& self, batch<T, A> const& other, requires_arch<generic>) noexcept |
131 | { |
132 | return detail::apply([](T x, T y) noexcept |
133 | { return x && y; }, |
134 | self, other); |
135 | } |
136 | |
137 | // logical_or |
138 | template <class A, class T> |
139 | inline batch<T, A> logical_or(batch<T, A> const& self, batch<T, A> const& other, requires_arch<generic>) noexcept |
140 | { |
141 | return detail::apply([](T x, T y) noexcept |
142 | { return x || y; }, |
143 | self, other); |
144 | } |
145 | |
146 | // mask |
147 | template <class A, class T> |
148 | inline uint64_t mask(batch_bool<T, A> const& self, requires_arch<generic>) noexcept |
149 | { |
150 | alignas(A::alignment()) bool buffer[batch_bool<T, A>::size]; |
151 | self.store_aligned(buffer); |
152 | // This is inefficient but should never be called. It's just a |
153 | // temporary implementation until arm support is added. |
154 | uint64_t res = 0; |
155 | for (size_t i = 0; i < batch_bool<T, A>::size; ++i) |
156 | if (buffer[i]) |
157 | res |= 1ul << i; |
158 | return res; |
159 | } |
160 | } |
161 | } |
162 | |
163 | #endif |
164 | |