Skip to content

Fix expm1 for complex inputs on the CPU backend#3760

Open
obchain wants to merge 1 commit into
ml-explore:mainfrom
obchain:fix/expm1-complex
Open

Fix expm1 for complex inputs on the CPU backend#3760
obchain wants to merge 1 commit into
ml-explore:mainfrom
obchain:fix/expm1-complex

Conversation

@obchain

@obchain obchain commented Jun 24, 2026

Copy link
Copy Markdown
Contributor

Proposed changes

Fixes #3759.

The CPU expm1 used std::expm1, which has no complex overload, so for a complex input it operated on the real part and discarded the imaginary part (e.g. expm1(0.5 + 0.7j) returned expm1(0.5) + 0j).

Added a complex branch to expm1 in base_simd.h that uses the defining identity exp(z) - 1, matching the complex handling already present for log1p and log2. The real and low-precision (Accelerate / fp16) paths are unchanged.

Before:

>>> mx.expm1(mx.array([0.5 + 0.7j]))
array([0.648721+0j], dtype=complex64)   # == expm1(0.5), wrong

After it equals exp(z) - 1.

Verified the complex forward now matches np.exp(z) - 1 and that the (already correct) Expm1::jvp agrees with finite differences for complex inputs; real and fp16 results are unchanged. Added a complex case to test_expm1.

Checklist

Put an x in the boxes that apply.

  • I have read the CONTRIBUTING document
  • I have run pre-commit run --all-files to format my code / installed pre-commit prior to committing changes
  • I have added tests that prove my fix is effective or that my feature works
  • I have updated the necessary documentation (if needed)

The CPU expm1 used std::expm1, which has no complex overload, so for a
complex input it operated on the real part and discarded the imaginary
part (e.g. expm1(0.5 + 0.7j) returned expm1(0.5) + 0j). Add a complex
branch that uses the defining identity exp(z) - 1, matching the complex
handling already present for log1p and log2. Real and low-precision
paths are unchanged.
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.

[BUG] mx.expm1 is wrong for complex inputs (discards imaginary part)

1 participant