From 753692ffb9c59c88f447a1856ad43c063f6f9d6b Mon Sep 17 00:00:00 2001 From: Vladislav Perevezentsev Date: Tue, 19 May 2026 07:01:44 -0700 Subject: [PATCH 1/4] Fix complex expm1 for zero input --- .../libtensor/include/kernels/elementwise_functions/expm1.hpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/dpnp/tensor/libtensor/include/kernels/elementwise_functions/expm1.hpp b/dpnp/tensor/libtensor/include/kernels/elementwise_functions/expm1.hpp index e9e2a704cf0..735cb1fada5 100644 --- a/dpnp/tensor/libtensor/include/kernels/elementwise_functions/expm1.hpp +++ b/dpnp/tensor/libtensor/include/kernels/elementwise_functions/expm1.hpp @@ -121,6 +121,10 @@ struct Expm1Functor } } + if (x == realT(0) && y == realT(0)) { + return resT{realT(0), y}; + } + // x, y finite numbers const realT cosY_val = sycl::cos(y); const realT sinY_val = (y == 0) ? y : sycl::sin(y); From ea3320b7e3c42b9e51315a9c1cc3c3ec49aec0e1 Mon Sep 17 00:00:00 2001 From: Vladislav Perevezentsev Date: Tue, 19 May 2026 07:03:26 -0700 Subject: [PATCH 2/4] Extend test_expm1_special_cases to add -0 case --- dpnp/tests/tensor/elementwise/test_expm1.py | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/dpnp/tests/tensor/elementwise/test_expm1.py b/dpnp/tests/tensor/elementwise/test_expm1.py index bb665c42456..e7c7765baa5 100644 --- a/dpnp/tests/tensor/elementwise/test_expm1.py +++ b/dpnp/tests/tensor/elementwise/test_expm1.py @@ -147,6 +147,7 @@ def test_expm1_special_cases(): num_finite = 1.0 vals = [ complex(0.0, 0.0), + complex(-0.0, 0.0), complex(num_finite, dpt.inf), complex(num_finite, dpt.nan), complex(dpt.inf, 0.0), @@ -165,6 +166,7 @@ def test_expm1_special_cases(): c_nan = complex(np.nan, np.nan) res = np.asarray( [ + complex(0.0, 0.0), complex(0.0, 0.0), c_nan, c_nan, @@ -184,4 +186,11 @@ def test_expm1_special_cases(): tol = dpt.finfo(X.dtype).resolution with np.errstate(invalid="ignore"): - assert_allclose(dpt.asnumpy(dpt.expm1(X)), res, atol=tol, rtol=tol) + Y = dpt.asnumpy(dpt.expm1(X)) + assert_allclose(Y, res, atol=tol, rtol=tol) + + # assert_allclose treats +0 == -0 + # verify sign bits for zero cases + for i in (0, 1): + assert not np.signbit(Y[i].real) + assert not np.signbit(Y[i].imag) From b8926d9343ce5fe560370958f5a1ccac8aa6faa4 Mon Sep 17 00:00:00 2001 From: Vladislav Perevezentsev Date: Tue, 19 May 2026 07:16:39 -0700 Subject: [PATCH 3/4] Update changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index dd3031c6547..6f24b204475 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -29,6 +29,7 @@ This release is compatible with NumPy 2.4.5. * Fixed `conda build` command syntax in GitHub workflows and documentation to use `conda-build` [#2888](https://github.com/IntelPython/dpnp/pull/2888) * Fixed incorrect `dpnp.tensor.acosh` result for `complex(±0, NaN)` special case to match the Python Array API specification [#2914](https://github.com/IntelPython/dpnp/pull/2914) * Fixed fork PR documentation workflow failures by implementing conditional publishing strategy: upstream PRs publish to GitHub Pages with comment, fork PRs upload artifacts [#2910](https://github.com/IntelPython/dpnp/pull/2910) +* Fixed incorrect `dpnp.tensor.expm1` result for `complex(±0, 0)` special case on CPU to match the Python Array API specification [#2926](https://github.com/IntelPython/dpnp/pull/2926) ### Security From d8c259ee018d4daab0378432c96c01f4bc3e9992 Mon Sep 17 00:00:00 2001 From: Vladislav Perevezentsev Date: Thu, 21 May 2026 07:07:19 -0700 Subject: [PATCH 4/4] Verify only real parts in test_expm1_special_cases --- dpnp/tests/tensor/elementwise/test_expm1.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/dpnp/tests/tensor/elementwise/test_expm1.py b/dpnp/tests/tensor/elementwise/test_expm1.py index e7c7765baa5..26e14840177 100644 --- a/dpnp/tests/tensor/elementwise/test_expm1.py +++ b/dpnp/tests/tensor/elementwise/test_expm1.py @@ -190,7 +190,6 @@ def test_expm1_special_cases(): assert_allclose(Y, res, atol=tol, rtol=tol) # assert_allclose treats +0 == -0 - # verify sign bits for zero cases + # verify sign bits for zero real parts for i in (0, 1): assert not np.signbit(Y[i].real) - assert not np.signbit(Y[i].imag)