-
-
Notifications
You must be signed in to change notification settings - Fork 11.1k
Open
Labels
Description
Describe the issue:
Writing the spec for complex number support in the Array API we found that NumPy currently fails in 4 special cases. The behavior is inconsistent with np.exp(z)-1
and C99 as shown in the code example.
The full list of special cases and specification is detailed in data-apis/array-api#452
cc @kgryte
Reproduce the code example:
import numpy as np
def is_equal(x, y):
"""Test whether two complex numbers are equal with special consideration for NaNs.
Parameters
----------
x : complex
First input number.
y : complex
Second input number.
Returns
-------
bool
Boolean indicating whether two complex numbers are equal.
Examples
--------
>>> import numpy as np
>>> is_equal(complex(np.nan, np.nan), complex(np.nan, np.nan))
True
"""
re1 = y.real
im1 = y.imag
re2 = x.real
im2 = x.imag
if re1 == re1:
if im1 == im1:
# Second value has non-NaN real and imaginary components, so test for component equality:
return (re1 == re2) and (im1 == im2)
if im2 == im2:
# Second value has a NaN imaginary component, but first value does not:
return False
# Both values have NaN imaginary components:
return True
if im1 == im1:
# Second value has a NaN real component, but a non-NaN imaginary component...
if re2 == re2:
# First value has a non-NaN real component:
return False
# Both values have NaN real components, so test for imaginary component equality:
return (im1 == im2)
if re2 == re2 or im2 == im2:
# Second value has real and imaginary components which are NaN, but first value does not:
return False
# Both values have real and imaginary components which are NaN:
return True
def compare(v, e):
actual = np.expm1(v)
print('Value: {value}'.format(value=str(v)))
print('Actual: {actual}'.format(actual=str(actual)))
print('Expected: {expected}'.format(expected=str(e)))
print('Equal: {is_equal}'.format(is_equal=str(is_equal(actual, e))))
print('\n')
# Case 1
v = complex(np.inf, 0.0)
e = complex(np.inf, 0.0)
compare(v, e) # np.exmp1 returns (inf+nanj), vs np.exp(complex(np.inf, 0.0))-1.0 == (inf+0j)
# Case 2
v = complex(-np.inf, np.inf)
e = complex(-1.0, 0.0)
compare(v, e) # np.exmp1 returns (nan+nanj), vs np.exp(complex(-np.inf, np.inf))-1.0 == (-1+0j)
# Case 3
v = complex(-np.inf, np.nan)
e = complex(-1.0, 0.0)
compare(v, e) # np.exmp1 returns (nan+nanj), vs np.exp(complex(-np.inf, np.nan))-1.0 == (-1+0j)
# Case 4
v = complex(np.nan, 0.0)
e = complex(np.nan, 0.0)
compare(v, e) # np.exmp1 returns (nan+nanj), vs np.exp(complex(np.nan, 0.0))-1.0 == (nan+0j)
Error message:
Value: (inf+0j)
Actual: (inf+nanj)
Expected: (inf+0j)
Equal: False
Value: (-inf+infj)
Actual: (nan+nanj)
Expected: (-1+0j)
Equal: False
Value: (-inf+nanj)
Actual: (nan+nanj)
Expected: (-1+0j)
Equal: False
Value: (nan+0j)
Actual: (nan+nanj)
Expected: (nan+0j)
Equal: False
NumPy/Python version information:
v1.22.4