Skip to content

Preserve complex arctangent branches and poles on the imaginary axis - #582

Open
antonsoo wants to merge 1 commit into
pydata:masterfrom
antonsoo:fix/complex-arctan-imaginary-axis
Open

antonsoo wants to merge 1 commit into
pydata:masterfrom
antonsoo:fix/complex-arctan-imaginary-axis

Conversation

@antonsoo

Copy link
Copy Markdown

The complex arctangent quotient loses the signed real zero on its branch cut and is undefined at the poles. An array containing 2j returns the wrong real branch; 1j returns NaNs:

import numpy as np
import numexpr as ne

z = np.array([2j, 1j])
print(ne.evaluate('arctan(z)'))
print(np.arctan(z))
# Before: [-1.57079633+0.54930614j, nan+nanj]
# After:  [ 1.57079633+0.54930614j,   0+infj]

Use std::atan for complex inputs whose real component is zero, preserving the principal branch and pole values. The other complex-input path keeps its existing arithmetic. Adds signed-zero/component assertions, both poles, strided arrays, execution-block crossings and aliased outputs; includes a release note.

The exact new method fails on the baseline and passes on the built extension with one and four threads. The full native numexpr.test() suite passes all 6,042 cases and project hooks pass. In 72 recorded-spectrum expressions checked against scalar cmath.atan, 70,728 incorrect bins become zero; all 18 ordinary off-axis control hashes are unchanged. This verifies expression values, without an acoustic-quality claim.

The independent square-root patch in #581 does not fix this arctangent path; its native head reproduces the same errors. Tested on Linux/Python 3.12 with NumPy 2.5.4 and the non-VML kernel. Other platforms and VML were not tested.

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