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_ARITHMETIC_HPP
13#define XSIMD_GENERIC_ARITHMETIC_HPP
14
15#include <complex>
16#include <type_traits>
17
18#include "./xsimd_generic_details.hpp"
19
20namespace xsimd
21{
22
23 namespace kernel
24 {
25
26 using namespace types;
27
28 // bitwise_lshift
29 template <class A, class T, class /*=typename std::enable_if<std::is_integral<T>::value, void>::type*/>
30 inline batch<T, A> bitwise_lshift(batch<T, A> const& self, batch<T, A> const& other, requires_arch<generic>) noexcept
31 {
32 return detail::apply([](T x, T y) noexcept
33 { return x << y; },
34 self, other);
35 }
36
37 // bitwise_rshift
38 template <class A, class T, class /*=typename std::enable_if<std::is_integral<T>::value, void>::type*/>
39 inline batch<T, A> bitwise_rshift(batch<T, A> const& self, batch<T, A> const& other, requires_arch<generic>) noexcept
40 {
41 return detail::apply([](T x, T y) noexcept
42 { return x >> y; },
43 self, other);
44 }
45
46 // div
47 template <class A, class T, class = typename std::enable_if<std::is_integral<T>::value, void>::type>
48 inline batch<T, A> div(batch<T, A> const& self, batch<T, A> const& other, requires_arch<generic>) noexcept
49 {
50 return detail::apply([](T x, T y) noexcept -> T
51 { return x / y; },
52 self, other);
53 }
54
55 // fma
56 template <class A, class T>
57 inline batch<T, A> fma(batch<T, A> const& x, batch<T, A> const& y, batch<T, A> const& z, requires_arch<generic>) noexcept
58 {
59 return x * y + z;
60 }
61
62 template <class A, class T>
63 inline batch<std::complex<T>, A> fma(batch<std::complex<T>, A> const& x, batch<std::complex<T>, A> const& y, batch<std::complex<T>, A> const& z, requires_arch<generic>) noexcept
64 {
65 auto res_r = fms(x.real(), y.real(), fms(x.imag(), y.imag(), z.real()));
66 auto res_i = fma(x.real(), y.imag(), fma(x.imag(), y.real(), z.imag()));
67 return { res_r, res_i };
68 }
69
70 // fms
71 template <class A, class T>
72 inline batch<T, A> fms(batch<T, A> const& x, batch<T, A> const& y, batch<T, A> const& z, requires_arch<generic>) noexcept
73 {
74 return x * y - z;
75 }
76
77 template <class A, class T>
78 inline batch<std::complex<T>, A> fms(batch<std::complex<T>, A> const& x, batch<std::complex<T>, A> const& y, batch<std::complex<T>, A> const& z, requires_arch<generic>) noexcept
79 {
80 auto res_r = fms(x.real(), y.real(), fma(x.imag(), y.imag(), z.real()));
81 auto res_i = fma(x.real(), y.imag(), fms(x.imag(), y.real(), z.imag()));
82 return { res_r, res_i };
83 }
84
85 // fnma
86 template <class A, class T>
87 inline batch<T, A> fnma(batch<T, A> const& x, batch<T, A> const& y, batch<T, A> const& z, requires_arch<generic>) noexcept
88 {
89 return -x * y + z;
90 }
91
92 template <class A, class T>
93 inline batch<std::complex<T>, A> fnma(batch<std::complex<T>, A> const& x, batch<std::complex<T>, A> const& y, batch<std::complex<T>, A> const& z, requires_arch<generic>) noexcept
94 {
95 auto res_r = -fms(x.real(), y.real(), fma(x.imag(), y.imag(), z.real()));
96 auto res_i = -fma(x.real(), y.imag(), fms(x.imag(), y.real(), z.imag()));
97 return { res_r, res_i };
98 }
99
100 // fnms
101 template <class A, class T>
102 inline batch<T, A> fnms(batch<T, A> const& x, batch<T, A> const& y, batch<T, A> const& z, requires_arch<generic>) noexcept
103 {
104 return -x * y - z;
105 }
106
107 template <class A, class T>
108 inline batch<std::complex<T>, A> fnms(batch<std::complex<T>, A> const& x, batch<std::complex<T>, A> const& y, batch<std::complex<T>, A> const& z, requires_arch<generic>) noexcept
109 {
110 auto res_r = -fms(x.real(), y.real(), fms(x.imag(), y.imag(), z.real()));
111 auto res_i = -fma(x.real(), y.imag(), fma(x.imag(), y.real(), z.imag()));
112 return { res_r, res_i };
113 }
114
115 // mul
116 template <class A, class T, class /*=typename std::enable_if<std::is_integral<T>::value, void>::type*/>
117 inline batch<T, A> mul(batch<T, A> const& self, batch<T, A> const& other, requires_arch<generic>) noexcept
118 {
119 return detail::apply([](T x, T y) noexcept -> T
120 { return x * y; },
121 self, other);
122 }
123
124 // sadd
125 template <class A>
126 inline batch<float, A> sadd(batch<float, A> const& self, batch<float, A> const& other, requires_arch<generic>) noexcept
127 {
128 return add(self, other); // no saturated arithmetic on floating point numbers
129 }
130 template <class A>
131 inline batch<double, A> sadd(batch<double, A> const& self, batch<double, A> const& other, requires_arch<generic>) noexcept
132 {
133 return add(self, other); // no saturated arithmetic on floating point numbers
134 }
135
136 // ssub
137 template <class A>
138 inline batch<float, A> ssub(batch<float, A> const& self, batch<float, A> const& other, requires_arch<generic>) noexcept
139 {
140 return sub(self, other); // no saturated arithmetic on floating point numbers
141 }
142 template <class A>
143 inline batch<double, A> ssub(batch<double, A> const& self, batch<double, A> const& other, requires_arch<generic>) noexcept
144 {
145 return sub(self, other); // no saturated arithmetic on floating point numbers
146 }
147
148 }
149
150}
151
152#endif
153