Skip to content

Commit 3c3fc82

Browse files
committed
[libcxx] Improve accuracy of complex exp
When computing exp(x + iy) with large x and small y, the naive computation exp(x) * (cos(y) + i*sin(y)) produces inf when exp(x) overflows, even though the result is finite when y is sufficiently small. Fix this with exp(x/2) * (cos(y) + i*sin(y)) * exp(x/2)
1 parent f03ccef commit 3c3fc82

File tree

2 files changed

+48
-0
lines changed

2 files changed

+48
-0
lines changed

libcxx/include/complex

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1091,6 +1091,10 @@ _LIBCPP_HIDE_FROM_ABI complex<_Tp> exp(const complex<_Tp>& __x) {
10911091
}
10921092
}
10931093
_Tp __e = std::exp(__x.real());
1094+
if (std::isinf(__e)) {
1095+
_Tp __e2 = std::exp(__x.real() * _Tp(0.5));
1096+
return complex<_Tp>(__e2 * std::cos(__i) * __e2, __e2 * std::sin(__i) * __e2);
1097+
}
10941098
return complex<_Tp>(__e * std::cos(__i), __e * std::sin(__i));
10951099
}
10961100

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
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+
// Tests for libc++-specific overflow handling behavior in complex exponential.
16+
// These tests validate implementation-specific handling of edge cases where
17+
// exp(real_part) overflows but the result should still be well-defined.
18+
19+
#include <complex>
20+
#include <cassert>
21+
#include <cmath>
22+
23+
#include "test_macros.h"
24+
25+
template <class T>
26+
void test_overflow_case() {
27+
typedef std::complex<T> C;
28+
29+
// In this case, the overflow of exp(real_part) is compensated when
30+
// sin(imag_part) is close to zero, resulting in a finite imaginary part.
31+
C z(T(90.0238094), T(5.900613e-39));
32+
C result = std::exp(z);
33+
34+
assert(std::isinf(result.real()));
35+
assert(result.real() > 0);
36+
37+
assert(std::isfinite(result.imag()));
38+
assert(std::abs(result.imag() - T(7.3746)) < T(1.0));
39+
}
40+
41+
int main(int, char**) {
42+
test_overflow_case<float>();
43+
return 0;
44+
}

0 commit comments

Comments
 (0)