1 //===------------------------- __complex_cmath.h --------------------------===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
9 // std::complex header copied from the libcxx source and simplified for use in
10 // OpenMP target offload regions.
12 //===----------------------------------------------------------------------===//
15 #error "This file is for OpenMP compilation only."
19 #error "This file is for C++ compilation only."
22 #ifndef _LIBCPP_COMPLEX
23 #define _LIBCPP_COMPLEX
26 #include <type_traits>
28 #define __DEVICE__ static constexpr __attribute__((nothrow))
34 template <class _Tp
> __DEVICE__ _Tp
abs(const std::complex<_Tp
> &__c
) {
35 return hypot(__c
.real(), __c
.imag());
40 template <class _Tp
> __DEVICE__ _Tp
arg(const std::complex<_Tp
> &__c
) {
41 return atan2(__c
.imag(), __c
.real());
45 typename enable_if
<is_integral
<_Tp
>::value
|| is_same
<_Tp
, double>::value
,
48 return atan2(0., __re
);
52 typename enable_if
<is_same
<_Tp
, float>::value
, float>::type
arg(_Tp __re
) {
53 return atan2f(0.F
, __re
);
58 template <class _Tp
> __DEVICE__ _Tp
norm(const std::complex<_Tp
> &__c
) {
59 if (std::isinf(__c
.real()))
60 return abs(__c
.real());
61 if (std::isinf(__c
.imag()))
62 return abs(__c
.imag());
63 return __c
.real() * __c
.real() + __c
.imag() * __c
.imag();
68 template <class _Tp
> std::complex<_Tp
> conj(const std::complex<_Tp
> &__c
) {
69 return std::complex<_Tp
>(__c
.real(), -__c
.imag());
74 template <class _Tp
> std::complex<_Tp
> proj(const std::complex<_Tp
> &__c
) {
75 std::complex<_Tp
> __r
= __c
;
76 if (std::isinf(__c
.real()) || std::isinf(__c
.imag()))
77 __r
= std::complex<_Tp
>(INFINITY
, copysign(_Tp(0), __c
.imag()));
84 complex<_Tp
> polar(const _Tp
&__rho
, const _Tp
&__theta
= _Tp()) {
85 if (std::isnan(__rho
) || signbit(__rho
))
86 return std::complex<_Tp
>(_Tp(NAN
), _Tp(NAN
));
87 if (std::isnan(__theta
)) {
88 if (std::isinf(__rho
))
89 return std::complex<_Tp
>(__rho
, __theta
);
90 return std::complex<_Tp
>(__theta
, __theta
);
92 if (std::isinf(__theta
)) {
93 if (std::isinf(__rho
))
94 return std::complex<_Tp
>(__rho
, _Tp(NAN
));
95 return std::complex<_Tp
>(_Tp(NAN
), _Tp(NAN
));
97 _Tp __x
= __rho
* cos(__theta
);
100 _Tp __y
= __rho
* sin(__theta
);
103 return std::complex<_Tp
>(__x
, __y
);
108 template <class _Tp
> std::complex<_Tp
> log(const std::complex<_Tp
> &__x
) {
109 return std::complex<_Tp
>(log(abs(__x
)), arg(__x
));
114 template <class _Tp
> std::complex<_Tp
> log10(const std::complex<_Tp
> &__x
) {
115 return log(__x
) / log(_Tp(10));
121 __DEVICE__
std::complex<_Tp
> sqrt(const std::complex<_Tp
> &__x
) {
122 if (std::isinf(__x
.imag()))
123 return std::complex<_Tp
>(_Tp(INFINITY
), __x
.imag());
124 if (std::isinf(__x
.real())) {
125 if (__x
.real() > _Tp(0))
126 return std::complex<_Tp
>(__x
.real(), std::isnan(__x
.imag())
128 : copysign(_Tp(0), __x
.imag()));
129 return std::complex<_Tp
>(std::isnan(__x
.imag()) ? __x
.imag() : _Tp(0),
130 copysign(__x
.real(), __x
.imag()));
132 return polar(sqrt(abs(__x
)), arg(__x
) / _Tp(2));
138 __DEVICE__
std::complex<_Tp
> exp(const std::complex<_Tp
> &__x
) {
139 _Tp __i
= __x
.imag();
140 if (std::isinf(__x
.real())) {
141 if (__x
.real() < _Tp(0)) {
142 if (!std::isfinite(__i
))
144 } else if (__i
== 0 || !std::isfinite(__i
)) {
147 return std::complex<_Tp
>(__x
.real(), __i
);
149 } else if (std::isnan(__x
.real()) && __x
.imag() == 0)
151 _Tp __e
= exp(__x
.real());
152 return std::complex<_Tp
>(__e
* cos(__i
), __e
* sin(__i
));
158 std::complex<_Tp
> pow(const std::complex<_Tp
> &__x
,
159 const std::complex<_Tp
> &__y
) {
160 return exp(__y
* log(__x
));
163 // __sqr, computes pow(x, 2)
165 template <class _Tp
> std::complex<_Tp
> __sqr(const std::complex<_Tp
> &__x
) {
166 return std::complex<_Tp
>((__x
.real() - __x
.imag()) *
167 (__x
.real() + __x
.imag()),
168 _Tp(2) * __x
.real() * __x
.imag());
174 __DEVICE__
std::complex<_Tp
> asinh(const std::complex<_Tp
> &__x
) {
175 const _Tp
__pi(atan2(+0., -0.));
176 if (std::isinf(__x
.real())) {
177 if (std::isnan(__x
.imag()))
179 if (std::isinf(__x
.imag()))
180 return std::complex<_Tp
>(__x
.real(),
181 copysign(__pi
* _Tp(0.25), __x
.imag()));
182 return std::complex<_Tp
>(__x
.real(), copysign(_Tp(0), __x
.imag()));
184 if (std::isnan(__x
.real())) {
185 if (std::isinf(__x
.imag()))
186 return std::complex<_Tp
>(__x
.imag(), __x
.real());
189 return std::complex<_Tp
>(__x
.real(), __x
.real());
191 if (std::isinf(__x
.imag()))
192 return std::complex<_Tp
>(copysign(__x
.imag(), __x
.real()),
193 copysign(__pi
/ _Tp(2), __x
.imag()));
194 std::complex<_Tp
> __z
= log(__x
+ sqrt(__sqr(__x
) + _Tp(1)));
195 return std::complex<_Tp
>(copysign(__z
.real(), __x
.real()),
196 copysign(__z
.imag(), __x
.imag()));
202 __DEVICE__
std::complex<_Tp
> acosh(const std::complex<_Tp
> &__x
) {
203 const _Tp
__pi(atan2(+0., -0.));
204 if (std::isinf(__x
.real())) {
205 if (std::isnan(__x
.imag()))
206 return std::complex<_Tp
>(abs(__x
.real()), __x
.imag());
207 if (std::isinf(__x
.imag())) {
209 return std::complex<_Tp
>(__x
.real(),
210 copysign(__pi
* _Tp(0.25), __x
.imag()));
212 return std::complex<_Tp
>(-__x
.real(),
213 copysign(__pi
* _Tp(0.75), __x
.imag()));
216 return std::complex<_Tp
>(-__x
.real(), copysign(__pi
, __x
.imag()));
217 return std::complex<_Tp
>(__x
.real(), copysign(_Tp(0), __x
.imag()));
219 if (std::isnan(__x
.real())) {
220 if (std::isinf(__x
.imag()))
221 return std::complex<_Tp
>(abs(__x
.imag()), __x
.real());
222 return std::complex<_Tp
>(__x
.real(), __x
.real());
224 if (std::isinf(__x
.imag()))
225 return std::complex<_Tp
>(abs(__x
.imag()),
226 copysign(__pi
/ _Tp(2), __x
.imag()));
227 std::complex<_Tp
> __z
= log(__x
+ sqrt(__sqr(__x
) - _Tp(1)));
228 return std::complex<_Tp
>(copysign(__z
.real(), _Tp(0)),
229 copysign(__z
.imag(), __x
.imag()));
235 __DEVICE__
std::complex<_Tp
> atanh(const std::complex<_Tp
> &__x
) {
236 const _Tp
__pi(atan2(+0., -0.));
237 if (std::isinf(__x
.imag())) {
238 return std::complex<_Tp
>(copysign(_Tp(0), __x
.real()),
239 copysign(__pi
/ _Tp(2), __x
.imag()));
241 if (std::isnan(__x
.imag())) {
242 if (std::isinf(__x
.real()) || __x
.real() == 0)
243 return std::complex<_Tp
>(copysign(_Tp(0), __x
.real()), __x
.imag());
244 return std::complex<_Tp
>(__x
.imag(), __x
.imag());
246 if (std::isnan(__x
.real())) {
247 return std::complex<_Tp
>(__x
.real(), __x
.real());
249 if (std::isinf(__x
.real())) {
250 return std::complex<_Tp
>(copysign(_Tp(0), __x
.real()),
251 copysign(__pi
/ _Tp(2), __x
.imag()));
253 if (abs(__x
.real()) == _Tp(1) && __x
.imag() == _Tp(0)) {
254 return std::complex<_Tp
>(copysign(_Tp(INFINITY
), __x
.real()),
255 copysign(_Tp(0), __x
.imag()));
257 std::complex<_Tp
> __z
= log((_Tp(1) + __x
) / (_Tp(1) - __x
)) / _Tp(2);
258 return std::complex<_Tp
>(copysign(__z
.real(), __x
.real()),
259 copysign(__z
.imag(), __x
.imag()));
265 __DEVICE__
std::complex<_Tp
> sinh(const std::complex<_Tp
> &__x
) {
266 if (std::isinf(__x
.real()) && !std::isfinite(__x
.imag()))
267 return std::complex<_Tp
>(__x
.real(), _Tp(NAN
));
268 if (__x
.real() == 0 && !std::isfinite(__x
.imag()))
269 return std::complex<_Tp
>(__x
.real(), _Tp(NAN
));
270 if (__x
.imag() == 0 && !std::isfinite(__x
.real()))
272 return std::complex<_Tp
>(sinh(__x
.real()) * cos(__x
.imag()),
273 cosh(__x
.real()) * sin(__x
.imag()));
279 __DEVICE__
std::complex<_Tp
> cosh(const std::complex<_Tp
> &__x
) {
280 if (std::isinf(__x
.real()) && !std::isfinite(__x
.imag()))
281 return std::complex<_Tp
>(abs(__x
.real()), _Tp(NAN
));
282 if (__x
.real() == 0 && !std::isfinite(__x
.imag()))
283 return std::complex<_Tp
>(_Tp(NAN
), __x
.real());
284 if (__x
.real() == 0 && __x
.imag() == 0)
285 return std::complex<_Tp
>(_Tp(1), __x
.imag());
286 if (__x
.imag() == 0 && !std::isfinite(__x
.real()))
287 return std::complex<_Tp
>(abs(__x
.real()), __x
.imag());
288 return std::complex<_Tp
>(cosh(__x
.real()) * cos(__x
.imag()),
289 sinh(__x
.real()) * sin(__x
.imag()));
295 __DEVICE__
std::complex<_Tp
> tanh(const std::complex<_Tp
> &__x
) {
296 if (std::isinf(__x
.real())) {
297 if (!std::isfinite(__x
.imag()))
298 return std::complex<_Tp
>(_Tp(1), _Tp(0));
299 return std::complex<_Tp
>(_Tp(1),
300 copysign(_Tp(0), sin(_Tp(2) * __x
.imag())));
302 if (std::isnan(__x
.real()) && __x
.imag() == 0)
304 _Tp
__2r(_Tp(2) * __x
.real());
305 _Tp
__2i(_Tp(2) * __x
.imag());
306 _Tp
__d(cosh(__2r
) + cos(__2i
));
307 _Tp
__2rsh(sinh(__2r
));
308 if (std::isinf(__2rsh
) && std::isinf(__d
))
309 return std::complex<_Tp
>(__2rsh
> _Tp(0) ? _Tp(1) : _Tp(-1),
310 __2i
> _Tp(0) ? _Tp(0) : _Tp(-0.));
311 return std::complex<_Tp
>(__2rsh
/ __d
, sin(__2i
) / __d
);
317 __DEVICE__
std::complex<_Tp
> asin(const std::complex<_Tp
> &__x
) {
318 std::complex<_Tp
> __z
= asinh(complex<_Tp
>(-__x
.imag(), __x
.real()));
319 return std::complex<_Tp
>(__z
.imag(), -__z
.real());
325 __DEVICE__
std::complex<_Tp
> acos(const std::complex<_Tp
> &__x
) {
326 const _Tp
__pi(atan2(+0., -0.));
327 if (std::isinf(__x
.real())) {
328 if (std::isnan(__x
.imag()))
329 return std::complex<_Tp
>(__x
.imag(), __x
.real());
330 if (std::isinf(__x
.imag())) {
331 if (__x
.real() < _Tp(0))
332 return std::complex<_Tp
>(_Tp(0.75) * __pi
, -__x
.imag());
333 return std::complex<_Tp
>(_Tp(0.25) * __pi
, -__x
.imag());
335 if (__x
.real() < _Tp(0))
336 return std::complex<_Tp
>(__pi
,
337 signbit(__x
.imag()) ? -__x
.real() : __x
.real());
338 return std::complex<_Tp
>(_Tp(0),
339 signbit(__x
.imag()) ? __x
.real() : -__x
.real());
341 if (std::isnan(__x
.real())) {
342 if (std::isinf(__x
.imag()))
343 return std::complex<_Tp
>(__x
.real(), -__x
.imag());
344 return std::complex<_Tp
>(__x
.real(), __x
.real());
346 if (std::isinf(__x
.imag()))
347 return std::complex<_Tp
>(__pi
/ _Tp(2), -__x
.imag());
348 if (__x
.real() == 0 && (__x
.imag() == 0 || isnan(__x
.imag())))
349 return std::complex<_Tp
>(__pi
/ _Tp(2), -__x
.imag());
350 std::complex<_Tp
> __z
= log(__x
+ sqrt(__sqr(__x
) - _Tp(1)));
351 if (signbit(__x
.imag()))
352 return std::complex<_Tp
>(abs(__z
.imag()), abs(__z
.real()));
353 return std::complex<_Tp
>(abs(__z
.imag()), -abs(__z
.real()));
359 __DEVICE__
std::complex<_Tp
> atan(const std::complex<_Tp
> &__x
) {
360 std::complex<_Tp
> __z
= atanh(complex<_Tp
>(-__x
.imag(), __x
.real()));
361 return std::complex<_Tp
>(__z
.imag(), -__z
.real());
367 __DEVICE__
std::complex<_Tp
> sin(const std::complex<_Tp
> &__x
) {
368 std::complex<_Tp
> __z
= sinh(complex<_Tp
>(-__x
.imag(), __x
.real()));
369 return std::complex<_Tp
>(__z
.imag(), -__z
.real());
374 template <class _Tp
> std::complex<_Tp
> cos(const std::complex<_Tp
> &__x
) {
375 return cosh(complex<_Tp
>(-__x
.imag(), __x
.real()));
381 __DEVICE__
std::complex<_Tp
> tan(const std::complex<_Tp
> &__x
) {
382 std::complex<_Tp
> __z
= tanh(complex<_Tp
>(-__x
.imag(), __x
.real()));
383 return std::complex<_Tp
>(__z
.imag(), -__z
.real());