Skip to content

Preserve signed imaginary zero in complex sqrt - #1433

Open
agourakis82 wants to merge 1 commit into
xtensor-stack:masterfrom
agourakis82:fix/complex-sqrt-signed-zero-1432
Open

agourakis82 wants to merge 1 commit into
xtensor-stack:masterfrom
agourakis82:fix/complex-sqrt-signed-zero-1432

Conversation

@agourakis82

Copy link
Copy Markdown

For finite real inputs on the real axis, xsimd::sqrt discards the sign of the imaginary zero. For example, sqrt(complex(-4, -0)) returns (0, 2) instead of (0, -2), selecting the wrong side of the branch cut. Positive real inputs and complex zero also lose an imaginary -0.

A standalone consumer also demonstrates a value-level consequence: composing the vectorized root with scalar std::exp(i * root) for (-4, -0) produces approximately 0.135335 before the fix, whereas the scalar reference produces 7.389056. After the fix the composition agrees with the reference. This is a synthetic composition that isolates the sqrt defect, not a claim of an observed failure in a downstream application.

Preserve the imaginary zero for nonnegative real inputs and use copysign for the imaginary root of negative real inputs. The real component remains nonnegative, including for a negative real zero.

The regression compares both components and their sign bits against std::sqrt for float and double, using mixed SIMD lanes. It covers both signs of imaginary zero with negative and positive normal values, the smallest subnormal, the largest finite value, and both real zeros. It is disabled under __FAST_MATH__, where signed-zero behavior is not guaranteed.

This addresses the finite real-axis sqrt cases from #1432. The other functions and non-real-axis cases reported there remain outside this change; this PR should not close the issue.

Native validation with GCC 13.3, C++23 and doctest 2.4.9:

  • The new regression fails against the unchanged base for both float and double in SSE2 and AVX2 builds, then passes with the fix.
  • All tests in test_complex_power.cpp pass in SSE2 and AVX2 builds.
  • The same unit passes AddressSanitizer and UndefinedBehaviorSanitizer.
  • The full CMake/CTest suite passes with TARGET_ARCH=sse2: 434 doctest cases, 78,104 assertions; CTest 1/1.
  • The original issue reproducer was run unchanged before and after the patch in both SIMD configurations; the two sqrt examples now agree with std::sqrt, while the other reported failures remain visible.

These are native Linux x86-64 results. Other architectures and official CI remain to be checked.

AI assistance was used to investigate the report, prepare the patch, and run validation.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant