Skip to content

Commit 11c9295

Browse files
committed
[libc++] Use libm implementations in exp for complex numbers
Replace the custom implementation with calls to compiler builtins, which delegate to libm implementations. This also improves accuracy, as demonstrated by the added test.
1 parent f03ccef commit 11c9295

File tree

2 files changed

+45
-16
lines changed

2 files changed

+45
-16
lines changed

libcxx/include/complex

Lines changed: 5 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1074,24 +1074,13 @@ _LIBCPP_HIDE_FROM_ABI complex<_Tp> sqrt(const complex<_Tp>& __x) {
10741074

10751075
// exp
10761076

1077+
_LIBCPP_HIDE_FROM_ABI inline _Complex float __cexp(_Complex float __v) { return __builtin_cexpf(__v); }
1078+
_LIBCPP_HIDE_FROM_ABI inline _Complex double __cexp(_Complex double __v) { return __builtin_cexp(__v); }
1079+
_LIBCPP_HIDE_FROM_ABI inline _Complex long double __cexp(_Complex long double __v) { return __builtin_cexpl(__v); }
1080+
10771081
template <class _Tp>
10781082
_LIBCPP_HIDE_FROM_ABI complex<_Tp> exp(const complex<_Tp>& __x) {
1079-
_Tp __i = __x.imag();
1080-
if (__i == 0) {
1081-
return complex<_Tp>(std::exp(__x.real()), std::copysign(_Tp(0), __x.imag()));
1082-
}
1083-
if (std::isinf(__x.real())) {
1084-
if (__x.real() < _Tp(0)) {
1085-
if (!std::isfinite(__i))
1086-
__i = _Tp(1);
1087-
} else if (__i == 0 || !std::isfinite(__i)) {
1088-
if (std::isinf(__i))
1089-
__i = _Tp(NAN);
1090-
return complex<_Tp>(__x.real(), __i);
1091-
}
1092-
}
1093-
_Tp __e = std::exp(__x.real());
1094-
return complex<_Tp>(__e * std::cos(__i), __e * std::sin(__i));
1083+
return complex<_Tp>(__from_builtin_tag(), std::__cexp(__x.__builtin()));
10951084
}
10961085

10971086
// pow
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
//===----------------------------------------------------------------------===//
2+
//
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
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
// <complex>
10+
11+
// template<class T>
12+
// complex<T>
13+
// exp(const complex<T>& x);
14+
15+
#include <complex>
16+
#include <cassert>
17+
#include <cmath>
18+
19+
#include "test_macros.h"
20+
21+
template <class T>
22+
void test_overflow_case() {
23+
typedef std::complex<T> C;
24+
25+
// In this case, the overflow of exp(real_part) is compensated when
26+
// sin(imag_part) is close to zero, resulting in a finite imaginary part.
27+
C z(T(90.0238094), T(5.900613e-39));
28+
C result = std::exp(z);
29+
30+
assert(std::isinf(result.real()));
31+
assert(result.real() > 0);
32+
33+
assert(std::isfinite(result.imag()));
34+
assert(std::abs(result.imag() - T(7.3746)) < T(1.0));
35+
}
36+
37+
int main(int, char**) {
38+
test_overflow_case<float>();
39+
return 0;
40+
}

0 commit comments

Comments
 (0)