|
110 | 110 | "mod",
|
111 | 111 | "modf",
|
112 | 112 | "multiply",
|
| 113 | + "nan_to_num", |
113 | 114 | "negative",
|
114 | 115 | "nextafter",
|
115 | 116 | "positive",
|
@@ -155,6 +156,13 @@ def _append_to_diff_array(a, axis, combined, values):
|
155 | 156 | combined.append(values)
|
156 | 157 |
|
157 | 158 |
|
| 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 | + |
158 | 166 | def _get_reduction_res_dt(a, dtype, _out):
|
159 | 167 | """Get a data type used by dpctl for result array in reduction function."""
|
160 | 168 |
|
@@ -2304,6 +2312,119 @@ def modf(x1, **kwargs):
|
2304 | 2312 | )
|
2305 | 2313 |
|
2306 | 2314 |
|
| 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 | + |
2307 | 2428 | _NEGATIVE_DOCSTRING = """
|
2308 | 2429 | Computes the numerical negative for each element `x_i` of input array `x`.
|
2309 | 2430 |
|
|
0 commit comments