[libcxx-commits] [libcxx] [libcxx] Improve accuracy of complex exp (PR #165254)
via libcxx-commits
libcxx-commits at lists.llvm.org
Mon Oct 27 07:00:18 PDT 2025
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-libcxx
Author: Aleksei Nurmukhametov (nurmukhametov)
<details>
<summary>Changes</summary>
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)`
---
Full diff: https://github.com/llvm/llvm-project/pull/165254.diff
2 Files Affected:
- (modified) libcxx/include/complex (+4)
- (added) libcxx/test/libcxx/numerics/complex.number/exp.pass.cpp (+44)
``````````diff
diff --git a/libcxx/include/complex b/libcxx/include/complex
index d8ec3d95c10ed..c749156e5d4f5 100644
--- a/libcxx/include/complex
+++ b/libcxx/include/complex
@@ -1091,6 +1091,10 @@ _LIBCPP_HIDE_FROM_ABI complex<_Tp> exp(const complex<_Tp>& __x) {
}
}
_Tp __e = std::exp(__x.real());
+ if (std::isinf(__e)) {
+ _Tp __e2 = std::exp(__x.real() * _Tp(0.5));
+ return complex<_Tp>(__e2 * std::cos(__i) * __e2, __e2 * std::sin(__i) * __e2);
+ }
return complex<_Tp>(__e * std::cos(__i), __e * std::sin(__i));
}
diff --git a/libcxx/test/libcxx/numerics/complex.number/exp.pass.cpp b/libcxx/test/libcxx/numerics/complex.number/exp.pass.cpp
new file mode 100644
index 0000000000000..74c4a1887a8ec
--- /dev/null
+++ b/libcxx/test/libcxx/numerics/complex.number/exp.pass.cpp
@@ -0,0 +1,44 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// <complex>
+
+// template<class T>
+// complex<T>
+// exp(const complex<T>& x);
+//
+// Tests for libc++-specific overflow handling behavior in complex exponential.
+// These tests validate implementation-specific handling of edge cases where
+// exp(real_part) overflows but the result should still be well-defined.
+
+#include <complex>
+#include <cassert>
+#include <cmath>
+
+#include "test_macros.h"
+
+template <class T>
+void test_overflow_case() {
+ typedef std::complex<T> C;
+
+ // In this case, the overflow of exp(real_part) is compensated when
+ // sin(imag_part) is close to zero, resulting in a finite imaginary part.
+ C z(T(90.0238094), T(5.900613e-39));
+ C result = std::exp(z);
+
+ assert(std::isinf(result.real()));
+ assert(result.real() > 0);
+
+ assert(std::isfinite(result.imag()));
+ assert(std::abs(result.imag() - T(7.3746)) < T(1.0));
+}
+
+int main(int, char**) {
+ test_overflow_case<float>();
+ return 0;
+}
``````````
</details>
https://github.com/llvm/llvm-project/pull/165254
More information about the libcxx-commits
mailing list