[libcxx-commits] [libcxx] [libcxx] Improve accuracy of complex exp (PR #165254)

Aleksei Nurmukhametov via libcxx-commits libcxx-commits at lists.llvm.org
Mon Oct 27 06:59:32 PDT 2025


https://github.com/nurmukhametov created https://github.com/llvm/llvm-project/pull/165254

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)

>From 3c3fc8209bef1ef744e6d185fb3663362d052751 Mon Sep 17 00:00:00 2001
From: Aleksei Nurmukhametov <anurmukh at amd.com>
Date: Mon, 27 Oct 2025 13:05:53 +0000
Subject: [PATCH] [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)
---
 libcxx/include/complex                        |  4 ++
 .../numerics/complex.number/exp.pass.cpp      | 44 +++++++++++++++++++
 2 files changed, 48 insertions(+)
 create mode 100644 libcxx/test/libcxx/numerics/complex.number/exp.pass.cpp

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;
+}



More information about the libcxx-commits mailing list