Skip to content

Commit eea6d1e

Browse files
Implement dpnp.nan_to_num()
1 parent 0c3dfe5 commit eea6d1e

File tree

1 file changed

+121
-0
lines changed

1 file changed

+121
-0
lines changed

dpnp/dpnp_iface_mathematical.py

Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,7 @@
110110
"mod",
111111
"modf",
112112
"multiply",
113+
"nan_to_num",
113114
"negative",
114115
"nextafter",
115116
"positive",
@@ -155,6 +156,13 @@ def _append_to_diff_array(a, axis, combined, values):
155156
combined.append(values)
156157

157158

159+
def _get_max_min(dtype):
160+
"""Get the maximum and minimum representable values for an inexact dtype."""
161+
162+
f = dpnp.finfo(dtype)
163+
return f.max, f.min
164+
165+
158166
def _get_reduction_res_dt(a, dtype, _out):
159167
"""Get a data type used by dpctl for result array in reduction function."""
160168

@@ -2304,6 +2312,119 @@ def modf(x1, **kwargs):
23042312
)
23052313

23062314

2315+
def nan_to_num(x, copy=True, nan=0.0, posinf=None, neginf=None):
2316+
"""
2317+
Replace NaN with zero and infinity with large finite numbers (default
2318+
behaviour) or with the numbers defined by the user using the `nan`,
2319+
`posinf` and/or `neginf` keywords.
2320+
2321+
If `x` is inexact, NaN is replaced by zero or by the user defined value in
2322+
`nan` keyword, infinity is replaced by the largest finite floating point
2323+
values representable by ``x.dtype`` or by the user defined value in
2324+
`posinf` keyword and -infinity is replaced by the most negative finite
2325+
floating point values representable by ``x.dtype`` or by the user defined
2326+
value in `neginf` keyword.
2327+
2328+
For complex dtypes, the above is applied to each of the real and
2329+
imaginary components of `x` separately.
2330+
2331+
If `x` is not inexact, then no replacements are made.
2332+
2333+
For full documentation refer to :obj:`numpy.nan_to_num`.
2334+
2335+
Parameters
2336+
----------
2337+
x : {dpnp.ndarray, usm_ndarray}
2338+
Input data.
2339+
copy : bool, optional
2340+
Whether to create a copy of `x` (True) or to replace values
2341+
in-place (False). The in-place operation only occurs if
2342+
casting to an array does not require a copy.
2343+
Default: ``True``.
2344+
nan : {int, float}, optional
2345+
Value to be used to fill NaN values.
2346+
Default: ``0.0``.
2347+
posinf : {int, float, None}, optional
2348+
Value to be used to fill positive infinity values. If no value is
2349+
passed then positive infinity values will be replaced with a very
2350+
large number.
2351+
Default: ``None``.
2352+
neginf : {int, float, None} optional
2353+
Value to be used to fill negative infinity values. If no value is
2354+
passed then negative infinity values will be replaced with a very
2355+
small (or negative) number.
2356+
Default: ``None``.
2357+
2358+
Returns
2359+
-------
2360+
out : dpnp.ndarray
2361+
`x`, with the non-finite values replaced. If `copy` is False, this may
2362+
be `x` itself.
2363+
2364+
See Also
2365+
--------
2366+
:obj:`dpnp.isinf` : Shows which elements are positive or negative infinity.
2367+
:obj:`dpnp.isneginf` : Shows which elements are negative infinity.
2368+
:obj:`dpnp.isposinf` : Shows which elements are positive infinity.
2369+
:obj:`dpnp.isnan` : Shows which elements are Not a Number (NaN).
2370+
:obj:`dpnp.isfinite` : Shows which elements are finite
2371+
(not NaN, not infinity)
2372+
2373+
Examples
2374+
--------
2375+
>>> import dpnp as np
2376+
>>> np.nan_to_num(np.array(np.inf))
2377+
array(1.79769313e+308)
2378+
>>> np.nan_to_num(np.array(-np.inf))
2379+
array(-1.79769313e+308)
2380+
>>> np.nan_to_num(np.array(np.nan))
2381+
array(0.)
2382+
>>> x = np.array([np.inf, -np.inf, np.nan, -128, 128])
2383+
>>> np.nan_to_num(x)
2384+
array([ 1.79769313e+308, -1.79769313e+308, 0.00000000e+000,
2385+
-1.28000000e+002, 1.28000000e+002])
2386+
>>> np.nan_to_num(x, nan=-9999, posinf=33333333, neginf=33333333)
2387+
array([ 3.3333333e+07, 3.3333333e+07, -9.9990000e+03, -1.2800000e+02,
2388+
1.2800000e+02])
2389+
>>> y = np.array([complex(np.inf, np.nan), np.nan, complex(np.nan, np.inf)])
2390+
>>> np.nan_to_num(y)
2391+
array([1.79769313e+308 +0.00000000e+000j, # may vary
2392+
0.00000000e+000 +0.00000000e+000j,
2393+
0.00000000e+000 +1.79769313e+308j])
2394+
>>> np.nan_to_num(y, nan=111111, posinf=222222)
2395+
array([222222.+111111.j, 111111. +0.j, 111111.+222222.j])
2396+
2397+
"""
2398+
2399+
dpnp.check_supported_arrays_type(x)
2400+
2401+
x = dpnp.array(x, copy=copy)
2402+
x_type = x.dtype.type
2403+
2404+
if not issubclass(x_type, dpnp.inexact):
2405+
return x
2406+
2407+
parts = (
2408+
(x.real, x.imag) if issubclass(x_type, dpnp.complexfloating) else (x,)
2409+
)
2410+
max_f, min_f = _get_max_min(x.real.dtype)
2411+
if posinf is not None:
2412+
max_f = posinf
2413+
if neginf is not None:
2414+
min_f = neginf
2415+
2416+
for part in parts:
2417+
nan_mask = dpnp.isnan(part)
2418+
posinf_mask = dpnp.isposinf(part)
2419+
neginf_mask = dpnp.isneginf(part)
2420+
2421+
part = dpnp.where(nan_mask, nan, part, out=part)
2422+
part = dpnp.where(posinf_mask, max_f, part, out=part)
2423+
part = dpnp.where(neginf_mask, min_f, part, out=part)
2424+
2425+
return x
2426+
2427+
23072428
_NEGATIVE_DOCSTRING = """
23082429
Computes the numerical negative for each element `x_i` of input array `x`.
23092430

0 commit comments

Comments
 (0)