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         // ge
26         template <class A, class T>
ge(batch<T,A> const & self,batch<T,A> const & other,requires_arch<generic>)27         inline batch_bool<T, A> ge(batch<T, A> const& self, batch<T, A> const& other, requires_arch<generic>) noexcept
28         {
29             return other <= self;
30         }
31 
32         // gt
33         template <class A, class T>
gt(batch<T,A> const & self,batch<T,A> const & other,requires_arch<generic>)34         inline batch_bool<T, A> gt(batch<T, A> const& self, batch<T, A> const& other, requires_arch<generic>) noexcept
35         {
36             return other < self;
37         }
38 
39         // is_even
40         template <class A, class T>
is_even(batch<T,A> const & self,requires_arch<generic>)41         inline batch_bool<T, A> is_even(batch<T, A> const& self, requires_arch<generic>) noexcept
42         {
43             return is_flint(self * T(0.5));
44         }
45 
46         // is_flint
47         template <class A, class T>
is_flint(batch<T,A> const & self,requires_arch<generic>)48         inline batch_bool<T, A> is_flint(batch<T, A> const& self, requires_arch<generic>) noexcept
49         {
50             auto frac = select(isnan(self - self), constants::nan<batch<T, A>>(), self - trunc(self));
51             return frac == T(0.);
52         }
53 
54         // is_odd
55         template <class A, class T>
is_odd(batch<T,A> const & self,requires_arch<generic>)56         inline batch_bool<T, A> is_odd(batch<T, A> const& self, requires_arch<generic>) noexcept
57         {
58             return is_even(self - T(1.));
59         }
60 
61         // isinf
62         template <class A, class T, class = typename std::enable_if<std::is_integral<T>::value, void>::type>
isinf(batch<T,A> const &,requires_arch<generic>)63         inline batch_bool<T, A> isinf(batch<T, A> const&, requires_arch<generic>) noexcept
64         {
65             return batch_bool<T, A>(false);
66         }
67         template <class A>
isinf(batch<float,A> const & self,requires_arch<generic>)68         inline batch_bool<float, A> isinf(batch<float, A> const& self, requires_arch<generic>) noexcept
69         {
70             return abs(self) == std::numeric_limits<float>::infinity();
71         }
72         template <class A>
isinf(batch<double,A> const & self,requires_arch<generic>)73         inline batch_bool<double, A> isinf(batch<double, A> const& self, requires_arch<generic>) noexcept
74         {
75             return abs(self) == std::numeric_limits<double>::infinity();
76         }
77 
78         // isfinite
79         template <class A, class T, class = typename std::enable_if<std::is_integral<T>::value, void>::type>
isfinite(batch<T,A> const &,requires_arch<generic>)80         inline batch_bool<T, A> isfinite(batch<T, A> const&, requires_arch<generic>) noexcept
81         {
82             return batch_bool<T, A>(true);
83         }
84         template <class A>
isfinite(batch<float,A> const & self,requires_arch<generic>)85         inline batch_bool<float, A> isfinite(batch<float, A> const& self, requires_arch<generic>) noexcept
86         {
87             return (self - self) == 0;
88         }
89         template <class A>
isfinite(batch<double,A> const & self,requires_arch<generic>)90         inline batch_bool<double, A> isfinite(batch<double, A> const& self, requires_arch<generic>) noexcept
91         {
92             return (self - self) == 0;
93         }
94 
95         // isnan
96         template <class A, class T, class = typename std::enable_if<std::is_integral<T>::value, void>::type>
isnan(batch<T,A> const &,requires_arch<generic>)97         inline batch_bool<T, A> isnan(batch<T, A> const&, requires_arch<generic>) noexcept
98         {
99             return batch_bool<T, A>(false);
100         }
101 
102         // le
103         template <class A, class T, class = typename std::enable_if<std::is_integral<T>::value, void>::type>
le(batch<T,A> const & self,batch<T,A> const & other,requires_arch<generic>)104         inline batch_bool<T, A> le(batch<T, A> const& self, batch<T, A> const& other, requires_arch<generic>) noexcept
105         {
106             return (self < other) || (self == other);
107         }
108 
109         // neq
110         template <class A, class T>
neq(batch<T,A> const & self,batch<T,A> const & other,requires_arch<generic>)111         inline batch_bool<T, A> neq(batch<T, A> const& self, batch<T, A> const& other, requires_arch<generic>) noexcept
112         {
113             return !(other == self);
114         }
115 
116         // logical_and
117         template <class A, class T>
logical_and(batch<T,A> const & self,batch<T,A> const & other,requires_arch<generic>)118         inline batch<T, A> logical_and(batch<T, A> const& self, batch<T, A> const& other, requires_arch<generic>) noexcept
119         {
120             return detail::apply([](T x, T y) noexcept
121                                  { return x && y; },
122                                  self, other);
123         }
124 
125         // logical_or
126         template <class A, class T>
logical_or(batch<T,A> const & self,batch<T,A> const & other,requires_arch<generic>)127         inline batch<T, A> logical_or(batch<T, A> const& self, batch<T, A> const& other, requires_arch<generic>) noexcept
128         {
129             return detail::apply([](T x, T y) noexcept
130                                  { return x || y; },
131                                  self, other);
132         }
133     }
134 }
135 
136 #endif
137