codekingpro/portable-devtools
114k
1import fnmatch
2import inspect
3import itertools
4import operator
5import platform
6import sys
7import warnings
8from collections import namedtuple
9from fractions import Fraction
10from functools import reduce
11
12import pytest
13
14import numpy as np
15import numpy._core.umath as ncu
16from numpy._core import _umath_tests as ncu_tests, sctypes
17from numpy.testing import (
18 HAS_REFCOUNT,
19 IS_MUSL,
20 IS_PYPY,
21 IS_WASM,
22 _gen_alignment_data,
23 assert_,
24 assert_allclose,
25 assert_almost_equal,
26 assert_array_almost_equal,
27 assert_array_almost_equal_nulp,
28 assert_array_equal,
29 assert_array_max_ulp,
30 assert_equal,
31 assert_no_warnings,
32 assert_raises,
33 assert_raises_regex,
34)
35from numpy.testing._private.utils import _glibc_older_than
36
37UFUNCS = [obj for obj in np._core.umath.__dict__.values()
38 if isinstance(obj, np.ufunc)]
39
40UFUNCS_UNARY = [
41 uf for uf in UFUNCS if uf.nin == 1
42]
43UFUNCS_UNARY_FP = [
44 uf for uf in UFUNCS_UNARY if 'f->f' in uf.types
45]
46
47UFUNCS_BINARY = [
48 uf for uf in UFUNCS if uf.nin == 2
49]
50UFUNCS_BINARY_ACC = [
51 uf for uf in UFUNCS_BINARY if hasattr(uf, "accumulate") and uf.nout == 1
52]
53
54def interesting_binop_operands(val1, val2, dtype):
55 """
56 Helper to create "interesting" operands to cover common code paths:
57 * scalar inputs
58 * only first "values" is an array (e.g. scalar division fast-paths)
59 * Longer array (SIMD) placing the value of interest at different positions
60 * Oddly strided arrays which may not be SIMD compatible
61
62 It does not attempt to cover unaligned access or mixed dtypes.
63 These are normally handled by the casting/buffering machinery.
64
65 This is not a fixture (currently), since I believe a fixture normally
66 only yields once?
67 """
68 fill_value = 1 # could be a parameter, but maybe not an optional one?
69
70 arr1 = np.full(10003, dtype=dtype, fill_value=fill_value)
71 arr2 = np.full(10003, dtype=dtype, fill_value=fill_value)
72
73 arr1[0] = val1
74 arr2[0] = val2
75
76 extractor = lambda res: res
77 yield arr1[0], arr2[0], extractor, "scalars"
78
79 extractor = lambda res: res
80 yield arr1[0, ...], arr2[0, ...], extractor, "scalar-arrays"
81
82 # reset array values to fill_value:
83 arr1[0] = fill_value
84 arr2[0] = fill_value
85
86 for pos in [0, 1, 2, 3, 4, 5, -1, -2, -3, -4]:
87 arr1[pos] = val1
88 arr2[pos] = val2
89
90 extractor = lambda res: res[pos]
91 yield arr1, arr2, extractor, f"off-{pos}"
92 yield arr1, arr2[pos], extractor, f"off-{pos}-with-scalar"
93
94 arr1[pos] = fill_value
95 arr2[pos] = fill_value
96
97 for stride in [-1, 113]:
98 op1 = arr1[::stride]
99 op2 = arr2[::stride]
100 op1[10] = val1
101 op2[10] = val2
102
103 extractor = lambda res: res[10]
104 yield op1, op2, extractor, f"stride-{stride}"
105
106 op1[10] = fill_value
107 op2[10] = fill_value
108
109
110def on_powerpc():
111 """ True if we are running on a Power PC platform."""
112 return platform.processor() == 'powerpc' or \
113 platform.machine().startswith('ppc')
114
115
116def bad_arcsinh():
117 """The blocklisted trig functions are not accurate on aarch64/PPC for
118 complex256. Rather than dig through the actual problem skip the
119 test. This should be fixed when we can move past glibc2.17
120 which is the version in manylinux2014
121 """
122 if platform.machine() == 'aarch64':
123 x = 1.78e-10
124 elif on_powerpc():
125 x = 2.16e-10
126 else:
127 return False
128 v1 = np.arcsinh(np.float128(x))
129 v2 = np.arcsinh(np.complex256(x)).real
130 # The eps for float128 is 1-e33, so this is way bigger
131 return abs((v1 / v2) - 1.0) > 1e-23
132
133
134class _FilterInvalids:
135 def setup_method(self):
136 self.olderr = np.seterr(invalid='ignore')
137
138 def teardown_method(self):
139 np.seterr(**self.olderr)
140
141
142class TestConstants:
143 def test_pi(self):
144 assert_allclose(ncu.pi, 3.141592653589793, 1e-15)
145
146 def test_e(self):
147 assert_allclose(ncu.e, 2.718281828459045, 1e-15)
148
149 def test_euler_gamma(self):
150 assert_allclose(ncu.euler_gamma, 0.5772156649015329, 1e-15)
151
152
153class TestOut:
154 def test_out_subok(self):
155 for subok in (True, False):
156 a = np.array(0.5)
157 o = np.empty(())
158
159 r = np.add(a, 2, o, subok=subok)
160 assert_(r is o)
161 r = np.add(a, 2, out=o, subok=subok)
162 assert_(r is o)
163 r = np.add(a, 2, out=(o,), subok=subok)
164 assert_(r is o)
165
166 d = np.array(5.7)
167 o1 = np.empty(())
168 o2 = np.empty((), dtype=np.int32)
169
170 r1, r2 = np.frexp(d, o1, None, subok=subok)
171 assert_(r1 is o1)
172 r1, r2 = np.frexp(d, None, o2, subok=subok)
173 assert_(r2 is o2)
174 r1, r2 = np.frexp(d, o1, o2, subok=subok)
175 assert_(r1 is o1)
176 assert_(r2 is o2)
177
178 r1, r2 = np.frexp(d, out=(o1, None), subok=subok)
179 assert_(r1 is o1)
180 r1, r2 = np.frexp(d, out=(None, o2), subok=subok)
181 assert_(r2 is o2)
182 r1, r2 = np.frexp(d, out=(o1, o2), subok=subok)
183 assert_(r1 is o1)
184 assert_(r2 is o2)
185
186 with assert_raises(TypeError):
187 # Out argument must be tuple, since there are multiple outputs.
188 r1, r2 = np.frexp(d, out=o1, subok=subok)
189
190 assert_raises(TypeError, np.add, a, 2, o, o, subok=subok)
191 assert_raises(TypeError, np.add, a, 2, o, out=o, subok=subok)
192 assert_raises(TypeError, np.add, a, 2, None, out=o, subok=subok)
193 assert_raises(ValueError, np.add, a, 2, out=(o, o), subok=subok)
194 assert_raises(ValueError, np.add, a, 2, out=(), subok=subok)
195 assert_raises(TypeError, np.add, a, 2, [], subok=subok)
196 assert_raises(TypeError, np.add, a, 2, out=[], subok=subok)
197 assert_raises(TypeError, np.add, a, 2, out=([],), subok=subok)
198 o.flags.writeable = False
199 assert_raises(ValueError, np.add, a, 2, o, subok=subok)
200 assert_raises(ValueError, np.add, a, 2, out=o, subok=subok)
201 assert_raises(ValueError, np.add, a, 2, out=(o,), subok=subok)
202
203 def test_out_wrap_subok(self):
204 class ArrayWrap(np.ndarray):
205 __array_priority__ = 10
206
207 def __new__(cls, arr):
208 return np.asarray(arr).view(cls).copy()
209
210 def __array_wrap__(self, arr, context=None, return_scalar=False):
211 return arr.view(type(self))
212
213 for subok in (True, False):
214 a = ArrayWrap([0.5])
215
216 r = np.add(a, 2, subok=subok)
217 if subok:
218 assert_(isinstance(r, ArrayWrap))
219 else:
220 assert_(type(r) == np.ndarray)
221
222 r = np.add(a, 2, None, subok=subok)
223 if subok:
224 assert_(isinstance(r, ArrayWrap))
225 else:
226 assert_(type(r) == np.ndarray)
227
228 r = np.add(a, 2, out=None, subok=subok)
229 if subok:
230 assert_(isinstance(r, ArrayWrap))
231 else:
232 assert_(type(r) == np.ndarray)
233
234 r = np.add(a, 2, out=(None,), subok=subok)
235 if subok:
236 assert_(isinstance(r, ArrayWrap))
237 else:
238 assert_(type(r) == np.ndarray)
239
240 d = ArrayWrap([5.7])
241 o1 = np.empty((1,))
242 o2 = np.empty((1,), dtype=np.int32)
243
244 r1, r2 = np.frexp(d, o1, subok=subok)
245 if subok:
246 assert_(isinstance(r2, ArrayWrap))
247 else:
248 assert_(type(r2) == np.ndarray)
249
250 r1, r2 = np.frexp(d, o1, None, subok=subok)
251 if subok:
252 assert_(isinstance(r2, ArrayWrap))
253 else:
254 assert_(type(r2) == np.ndarray)
255
256 r1, r2 = np.frexp(d, None, o2, subok=subok)
257 if subok:
258 assert_(isinstance(r1, ArrayWrap))
259 else:
260 assert_(type(r1) == np.ndarray)
261
262 r1, r2 = np.frexp(d, out=(o1, None), subok=subok)
263 if subok:
264 assert_(isinstance(r2, ArrayWrap))
265 else:
266 assert_(type(r2) == np.ndarray)
267
268 r1, r2 = np.frexp(d, out=(None, o2), subok=subok)
269 if subok:
270 assert_(isinstance(r1, ArrayWrap))
271 else:
272 assert_(type(r1) == np.ndarray)
273
274 with assert_raises(TypeError):
275 # Out argument must be tuple, since there are multiple outputs.
276 r1, r2 = np.frexp(d, out=o1, subok=subok)
277
278 @pytest.mark.skipif(not HAS_REFCOUNT, reason="Python lacks refcounts")
279 def test_out_wrap_no_leak(self):
280 # Regression test for gh-26545
281 class ArrSubclass(np.ndarray):
282 pass
283
284 arr = np.arange(10).view(ArrSubclass)
285 orig_refcount = sys.getrefcount(arr)
286 arr *= 1
287 assert sys.getrefcount(arr) == orig_refcount
288
289
290class TestComparisons:
291 import operator
292
293 @pytest.mark.parametrize('dtype', sctypes['uint'] + sctypes['int'] +
294 sctypes['float'] + [np.bool])
295 @pytest.mark.parametrize('py_comp,np_comp', [
296 (operator.lt, np.less),
297 (operator.le, np.less_equal),
298 (operator.gt, np.greater),
299 (operator.ge, np.greater_equal),
300 (operator.eq, np.equal),
301 (operator.ne, np.not_equal)
302 ])
303 def test_comparison_functions(self, dtype, py_comp, np_comp):
304 # Initialize input arrays
305 if dtype == np.bool:
306 a = np.random.choice(a=[False, True], size=1000)
307 b = np.random.choice(a=[False, True], size=1000)
308 scalar = True
309 else:
310 a = np.random.randint(low=1, high=10, size=1000).astype(dtype)
311 b = np.random.randint(low=1, high=10, size=1000).astype(dtype)
312 scalar = 5
313 np_scalar = np.dtype(dtype).type(scalar)
314 a_lst = a.tolist()
315 b_lst = b.tolist()
316
317 # (Binary) Comparison (x1=array, x2=array)
318 comp_b = np_comp(a, b).view(np.uint8)
319 comp_b_list = [int(py_comp(x, y)) for x, y in zip(a_lst, b_lst)]
320
321 # (Scalar1) Comparison (x1=scalar, x2=array)
322 comp_s1 = np_comp(np_scalar, b).view(np.uint8)
323 comp_s1_list = [int(py_comp(scalar, x)) for x in b_lst]
324
325 # (Scalar2) Comparison (x1=array, x2=scalar)
326 comp_s2 = np_comp(a, np_scalar).view(np.uint8)
327 comp_s2_list = [int(py_comp(x, scalar)) for x in a_lst]
328
329 # Sequence: Binary, Scalar1 and Scalar2
330 assert_(comp_b.tolist() == comp_b_list,
331 f"Failed comparison ({py_comp.__name__})")
332 assert_(comp_s1.tolist() == comp_s1_list,
333 f"Failed comparison ({py_comp.__name__})")
334 assert_(comp_s2.tolist() == comp_s2_list,
335 f"Failed comparison ({py_comp.__name__})")
336
337 def test_ignore_object_identity_in_equal(self):
338 # Check comparing identical objects whose comparison
339 # is not a simple boolean, e.g., arrays that are compared elementwise.
340 a = np.array([np.array([1, 2, 3]), None], dtype=object)
341 assert_raises(ValueError, np.equal, a, a)
342
343 # Check error raised when comparing identical non-comparable objects.
344 class FunkyType:
345 def __eq__(self, other):
346 raise TypeError("I won't compare")
347
348 a = np.array([FunkyType()])
349 assert_raises(TypeError, np.equal, a, a)
350
351 # Check identity doesn't override comparison mismatch.
352 a = np.array([np.nan], dtype=object)
353 assert_equal(np.equal(a, a), [False])
354
355 def test_ignore_object_identity_in_not_equal(self):
356 # Check comparing identical objects whose comparison
357 # is not a simple boolean, e.g., arrays that are compared elementwise.
358 a = np.array([np.array([1, 2, 3]), None], dtype=object)
359 assert_raises(ValueError, np.not_equal, a, a)
360
361 # Check error raised when comparing identical non-comparable objects.
362 class FunkyType:
363 def __ne__(self, other):
364 raise TypeError("I won't compare")
365
366 a = np.array([FunkyType()])
367 assert_raises(TypeError, np.not_equal, a, a)
368
369 # Check identity doesn't override comparison mismatch.
370 a = np.array([np.nan], dtype=object)
371 assert_equal(np.not_equal(a, a), [True])
372
373 def test_error_in_equal_reduce(self):
374 # gh-20929
375 # make sure np.equal.reduce raises a TypeError if an array is passed
376 # without specifying the dtype
377 a = np.array([0, 0])
378 assert_equal(np.equal.reduce(a, dtype=bool), True)
379 assert_raises(TypeError, np.equal.reduce, a)
380
381 def test_object_dtype(self):
382 assert np.equal(1, [1], dtype=object).dtype == object
383 assert np.equal(1, [1], signature=(None, None, "O")).dtype == object
384
385 def test_object_nonbool_dtype_error(self):
386 # bool output dtype is fine of course:
387 assert np.equal(1, [1], dtype=bool).dtype == bool
388
389 # but the following are examples do not have a loop:
390 with pytest.raises(TypeError, match="No loop matching"):
391 np.equal(1, 1, dtype=np.int64)
392
393 with pytest.raises(TypeError, match="No loop matching"):
394 np.equal(1, 1, sig=(None, None, "l"))
395
396 @pytest.mark.parametrize("dtypes", ["qQ", "Qq"])
397 @pytest.mark.parametrize('py_comp, np_comp', [
398 (operator.lt, np.less),
399 (operator.le, np.less_equal),
400 (operator.gt, np.greater),
401 (operator.ge, np.greater_equal),
402 (operator.eq, np.equal),
403 (operator.ne, np.not_equal)
404 ])
405 @pytest.mark.parametrize("vals", [(2**60, 2**60 + 1), (2**60 + 1, 2**60)])
406 def test_large_integer_direct_comparison(
407 self, dtypes, py_comp, np_comp, vals):
408 # Note that float(2**60) + 1 == float(2**60).
409 a1 = np.array([2**60], dtype=dtypes[0])
410 a2 = np.array([2**60 + 1], dtype=dtypes[1])
411 expected = py_comp(2**60, 2**60 + 1)
412
413 assert py_comp(a1, a2) == expected
414 assert np_comp(a1, a2) == expected
415 # Also check the scalars:
416 s1 = a1[0]
417 s2 = a2[0]
418 assert isinstance(s1, np.integer)
419 assert isinstance(s2, np.integer)
420 # The Python operator here is mainly interesting:
421 assert py_comp(s1, s2) == expected
422 assert np_comp(s1, s2) == expected
423
424 @pytest.mark.parametrize("dtype", np.typecodes['UnsignedInteger'])
425 @pytest.mark.parametrize('py_comp_func, np_comp_func', [
426 (operator.lt, np.less),
427 (operator.le, np.less_equal),
428 (operator.gt, np.greater),
429 (operator.ge, np.greater_equal),
430 (operator.eq, np.equal),
431 (operator.ne, np.not_equal)
432 ])
433 @pytest.mark.parametrize("flip", [True, False])
434 def test_unsigned_signed_direct_comparison(
435 self, dtype, py_comp_func, np_comp_func, flip):
436 if flip:
437 py_comp = lambda x, y: py_comp_func(y, x)
438 np_comp = lambda x, y: np_comp_func(y, x)
439 else:
440 py_comp = py_comp_func
441 np_comp = np_comp_func
442
443 arr = np.array([np.iinfo(dtype).max], dtype=dtype)
444 expected = py_comp(int(arr[0]), -1)
445
446 assert py_comp(arr, -1) == expected
447 assert np_comp(arr, -1) == expected
448
449 scalar = arr[0]
450 assert isinstance(scalar, np.integer)
451 # The Python operator here is mainly interesting:
452 assert py_comp(scalar, -1) == expected
453 assert np_comp(scalar, -1) == expected
454
455
456class TestAdd:
457 def test_reduce_alignment(self):
458 # gh-9876
459 # make sure arrays with weird strides work with the optimizations in
460 # pairwise_sum_@TYPE@. On x86, the 'b' field will count as aligned at a
461 # 4 byte offset, even though its itemsize is 8.
462 a = np.zeros(2, dtype=[('a', np.int32), ('b', np.float64)])
463 a['a'] = -1
464 assert_equal(a['b'].sum(), 0)
465
466
467class TestDivision:
468 def test_division_int(self):
469 # int division should follow Python
470 x = np.array([5, 10, 90, 100, -5, -10, -90, -100, -120])
471 if 5 / 10 == 0.5:
472 assert_equal(x / 100, [0.05, 0.1, 0.9, 1,
473 -0.05, -0.1, -0.9, -1, -1.2])
474 else:
475 assert_equal(x / 100, [0, 0, 0, 1, -1, -1, -1, -1, -2])
476 assert_equal(x // 100, [0, 0, 0, 1, -1, -1, -1, -1, -2])
477 assert_equal(x % 100, [5, 10, 90, 0, 95, 90, 10, 0, 80])
478
479 @pytest.mark.skipif(IS_WASM, reason="fp errors don't work in wasm")
480 @pytest.mark.parametrize("dtype,ex_val", itertools.product(
481 sctypes['int'] + sctypes['uint'], (
482 (
483 # dividend
484 "np.array(range(fo.max-lsize, fo.max)).astype(dtype),"
485 # divisors
486 "np.arange(lsize).astype(dtype),"
487 # scalar divisors
488 "range(15)"
489 ),
490 (
491 # dividend
492 "np.arange(fo.min, fo.min+lsize).astype(dtype),"
493 # divisors
494 "np.arange(lsize//-2, lsize//2).astype(dtype),"
495 # scalar divisors
496 "range(fo.min, fo.min + 15)"
497 ), (
498 # dividend
499 "np.array(range(fo.max-lsize, fo.max)).astype(dtype),"
500 # divisors
501 "np.arange(lsize).astype(dtype),"
502 # scalar divisors
503 "[1,3,9,13,neg, fo.min+1, fo.min//2, fo.max//3, fo.max//4]"
504 )
505 )
506 ))
507 def test_division_int_boundary(self, dtype, ex_val):
508 fo = np.iinfo(dtype)
509 neg = -1 if fo.min < 0 else 1
510 # Large enough to test SIMD loops and remainder elements
511 lsize = 512 + 7
512 a, b, divisors = eval(ex_val)
513 a_lst, b_lst = a.tolist(), b.tolist()
514
515 c_div = lambda n, d: (
516 0 if d == 0 else (
517 fo.min if (n and n == fo.min and d == -1) else n // d
518 )
519 )
520 with np.errstate(divide='ignore'):
521 ac = a.copy()
522 ac //= b
523 div_ab = a // b
524 div_lst = [c_div(x, y) for x, y in zip(a_lst, b_lst)]
525
526 msg = "Integer arrays floor division check (//)"
527 assert all(div_ab == div_lst), msg
528 msg_eq = "Integer arrays floor division check (//=)"
529 assert all(ac == div_lst), msg_eq
530
531 for divisor in divisors:
532 ac = a.copy()
533 with np.errstate(divide='ignore', over='ignore'):
534 div_a = a // divisor
535 ac //= divisor
536 div_lst = [c_div(i, divisor) for i in a_lst]
537
538 assert all(div_a == div_lst), msg
539 assert all(ac == div_lst), msg_eq
540
541 with np.errstate(divide='raise', over='raise'):
542 if 0 in b:
543 # Verify overflow case
544 with pytest.raises(FloatingPointError,
545 match="divide by zero encountered in floor_divide"):
546 a // b
547 else:
548 a // b
549 if fo.min and fo.min in a:
550 with pytest.raises(FloatingPointError,
551 match='overflow encountered in floor_divide'):
552 a // -1
553 elif fo.min:
554 a // -1
555 with pytest.raises(FloatingPointError,
556 match="divide by zero encountered in floor_divide"):
557 a // 0
558 with pytest.raises(FloatingPointError,
559 match="divide by zero encountered in floor_divide"):
560 ac = a.copy()
561 ac //= 0
562
563 np.array([], dtype=dtype) // 0
564
565 @pytest.mark.skipif(IS_WASM, reason="fp errors don't work in wasm")
566 @pytest.mark.parametrize("dtype,ex_val", itertools.product(
567 sctypes['int'] + sctypes['uint'], (
568 "np.array([fo.max, 1, 2, 1, 1, 2, 3], dtype=dtype)",
569 "np.array([fo.min, 1, -2, 1, 1, 2, -3]).astype(dtype)",
570 "np.arange(fo.min, fo.min+(100*10), 10, dtype=dtype)",
571 "np.array(range(fo.max-(100*7), fo.max, 7)).astype(dtype)",
572 )
573 ))
574 def test_division_int_reduce(self, dtype, ex_val):
575 fo = np.iinfo(dtype)
576 a = eval(ex_val)
577 lst = a.tolist()
578 c_div = lambda n, d: (
579 0 if d == 0 or (n and n == fo.min and d == -1) else n // d
580 )
581
582 with np.errstate(divide='ignore'):
583 div_a = np.floor_divide.reduce(a)
584 div_lst = reduce(c_div, lst)
585 msg = "Reduce floor integer division check"
586 assert div_a == div_lst, msg
587
588 with np.errstate(divide='raise', over='raise'):
589 with pytest.raises(FloatingPointError,
590 match="divide by zero encountered in reduce"):
591 np.floor_divide.reduce(np.arange(-100, 100).astype(dtype))
592 if fo.min:
593 with pytest.raises(FloatingPointError,
594 match='overflow encountered in reduce'):
595 np.floor_divide.reduce(
596 np.array([fo.min, 1, -1], dtype=dtype)
597 )
598
599 @pytest.mark.parametrize(
600 "dividend,divisor,quotient",
601 [(np.timedelta64(2, 'Y'), np.timedelta64(2, 'M'), 12),
602 (np.timedelta64(2, 'Y'), np.timedelta64(-2, 'M'), -12),
603 (np.timedelta64(-2, 'Y'), np.timedelta64(2, 'M'), -12),
604 (np.timedelta64(-2, 'Y'), np.timedelta64(-2, 'M'), 12),
605 (np.timedelta64(2, 'M'), np.timedelta64(-2, 'Y'), -1),
606 (np.timedelta64(2, 'Y'), np.timedelta64(0, 'M'), 0),
607 (np.timedelta64(2, 'Y'), 2, np.timedelta64(1, 'Y')),
608 (np.timedelta64(2, 'Y'), -2, np.timedelta64(-1, 'Y')),
609 (np.timedelta64(-2, 'Y'), 2, np.timedelta64(-1, 'Y')),
610 (np.timedelta64(-2, 'Y'), -2, np.timedelta64(1, 'Y')),
611 (np.timedelta64(-2, 'Y'), -2, np.timedelta64(1, 'Y')),
612 (np.timedelta64(-2, 'Y'), -3, np.timedelta64(0, 'Y')),
613 (np.timedelta64(-2, 'Y'), 0, np.timedelta64('Nat', 'Y')),
614 ])
615 def test_division_int_timedelta(self, dividend, divisor, quotient):
616 # If either divisor is 0 or quotient is Nat, check for division by 0
617 if divisor and (isinstance(quotient, int) or not np.isnat(quotient)):
618 msg = "Timedelta floor division check"
619 assert dividend // divisor == quotient, msg
620
621 # Test for arrays as well
622 msg = "Timedelta arrays floor division check"
623 dividend_array = np.array([dividend] * 5)
624 quotient_array = np.array([quotient] * 5)
625 assert all(dividend_array // divisor == quotient_array), msg
626 else:
627 if IS_WASM:
628 pytest.skip("fp errors don't work in wasm")
629 with np.errstate(divide='raise', invalid='raise'):
630 with pytest.raises(FloatingPointError):
631 dividend // divisor
632
633 def test_division_complex(self):
634 # check that implementation is correct
635 msg = "Complex division implementation check"
636 x = np.array([1. + 1. * 1j, 1. + .5 * 1j, 1. + 2. * 1j], dtype=np.complex128)
637 assert_almost_equal(x**2 / x, x, err_msg=msg)
638 # check overflow, underflow
639 msg = "Complex division overflow/underflow check"
640 x = np.array([1.e+110, 1.e-110], dtype=np.complex128)
641 y = x**2 / x
642 assert_almost_equal(y / x, [1, 1], err_msg=msg)
643
644 def test_zero_division_complex(self):
645 with np.errstate(invalid="ignore", divide="ignore"):
646 x = np.array([0.0], dtype=np.complex128)
647 y = 1.0 / x
648 assert_(np.isinf(y)[0])
649 y = complex(np.inf, np.nan) / x
650 assert_(np.isinf(y)[0])
651 y = complex(np.nan, np.inf) / x
652 assert_(np.isinf(y)[0])
653 y = complex(np.inf, np.inf) / x
654 assert_(np.isinf(y)[0])
655 y = 0.0 / x
656 assert_(np.isnan(y)[0])
657
658 def test_floor_division_complex(self):
659 # check that floor division, divmod and remainder raises type errors
660 x = np.array([.9 + 1j, -.1 + 1j, .9 + .5 * 1j, .9 + 2. * 1j], dtype=np.complex128)
661 with pytest.raises(TypeError):
662 x // 7
663 with pytest.raises(TypeError):
664 np.divmod(x, 7)
665 with pytest.raises(TypeError):
666 np.remainder(x, 7)
667
668 def test_floor_division_signed_zero(self):
669 # Check that the sign bit is correctly set when dividing positive and
670 # negative zero by one.
671 x = np.zeros(10)
672 assert_equal(np.signbit(x // 1), 0)
673 assert_equal(np.signbit((-x) // 1), 1)
674
675 @pytest.mark.skipif(hasattr(np.__config__, "blas_ssl2_info"),
676 reason="gh-22982")
677 @pytest.mark.skipif(IS_WASM, reason="fp errors don't work in wasm")
678 @pytest.mark.parametrize('dtype', np.typecodes['Float'])
679 def test_floor_division_errors(self, dtype):
680 fnan = np.array(np.nan, dtype=dtype)
681 fone = np.array(1.0, dtype=dtype)
682 fzer = np.array(0.0, dtype=dtype)
683 finf = np.array(np.inf, dtype=dtype)
684 # divide by zero error check
685 with np.errstate(divide='raise', invalid='ignore'):
686 assert_raises(FloatingPointError, np.floor_divide, fone, fzer)
687 with np.errstate(divide='ignore', invalid='raise'):
688 np.floor_divide(fone, fzer)
689
690 # The following already contain a NaN and should not warn
691 with np.errstate(all='raise'):
692 np.floor_divide(fnan, fone)
693 np.floor_divide(fone, fnan)
694 np.floor_divide(fnan, fzer)
695 np.floor_divide(fzer, fnan)
696
697 @pytest.mark.parametrize('dtype', np.typecodes['Float'])
698 def test_floor_division_corner_cases(self, dtype):
699 # test corner cases like 1.0//0.0 for errors and return vals
700 x = np.zeros(10, dtype=dtype)
701 y = np.ones(10, dtype=dtype)
702 fnan = np.array(np.nan, dtype=dtype)
703 fone = np.array(1.0, dtype=dtype)
704 fzer = np.array(0.0, dtype=dtype)
705 finf = np.array(np.inf, dtype=dtype)
706 with warnings.catch_warnings():
707 warnings.filterwarnings('ignore', "invalid value encountered in floor_divide", RuntimeWarning)
708 div = np.floor_divide(fnan, fone)
709 assert np.isnan(div), f"div: {div}"
710 div = np.floor_divide(fone, fnan)
711 assert np.isnan(div), f"div: {div}"
712 div = np.floor_divide(fnan, fzer)
713 assert np.isnan(div), f"div: {div}"
714 # verify 1.0//0.0 computations return inf
715 with np.errstate(divide='ignore'):
716 z = np.floor_divide(y, x)
717 assert_(np.isinf(z).all())
718
719def floor_divide_and_remainder(x, y):
720 return (np.floor_divide(x, y), np.remainder(x, y))
721
722
723def _signs(dt):
724 if dt in np.typecodes['UnsignedInteger']:
725 return (+1,)
726 else:
727 return (+1, -1)
728
729
730class TestRemainder:
731
732 def test_remainder_basic(self):
733 dt = np.typecodes['AllInteger'] + np.typecodes['Float']
734 for op in [floor_divide_and_remainder, np.divmod]:
735 for dt1, dt2 in itertools.product(dt, dt):
736 for sg1, sg2 in itertools.product(_signs(dt1), _signs(dt2)):
737 fmt = 'op: %s, dt1: %s, dt2: %s, sg1: %s, sg2: %s'
738 msg = fmt % (op.__name__, dt1, dt2, sg1, sg2)
739 a = np.array(sg1 * 71, dtype=dt1)
740 b = np.array(sg2 * 19, dtype=dt2)
741 div, rem = op(a, b)
742 assert_equal(div * b + rem, a, err_msg=msg)
743 if sg2 == -1:
744 assert_(b < rem <= 0, msg)
745 else:
746 assert_(b > rem >= 0, msg)
747
748 def test_float_remainder_exact(self):
749 # test that float results are exact for small integers. This also
750 # holds for the same integers scaled by powers of two.
751 nlst = list(range(-127, 0))
752 plst = list(range(1, 128))
753 dividend = nlst + [0] + plst
754 divisor = nlst + plst
755 arg = list(itertools.product(dividend, divisor))
756 tgt = [divmod(*t) for t in arg]
757
758 a, b = np.array(arg, dtype=int).T
759 # convert exact integer results from Python to float so that
760 # signed zero can be used, it is checked.
761 tgtdiv, tgtrem = np.array(tgt, dtype=float).T
762 tgtdiv = np.where((tgtdiv == 0.0) & ((b < 0) ^ (a < 0)), -0.0, tgtdiv)
763 tgtrem = np.where((tgtrem == 0.0) & (b < 0), -0.0, tgtrem)
764
765 for op in [floor_divide_and_remainder, np.divmod]:
766 for dt in np.typecodes['Float']:
767 msg = f'op: {op.__name__}, dtype: {dt}'
768 fa = a.astype(dt)
769 fb = b.astype(dt)
770 div, rem = op(fa, fb)
771 assert_equal(div, tgtdiv, err_msg=msg)
772 assert_equal(rem, tgtrem, err_msg=msg)
773
774 def test_float_remainder_roundoff(self):
775 # gh-6127
776 dt = np.typecodes['Float']
777 for op in [floor_divide_and_remainder, np.divmod]:
778 for dt1, dt2 in itertools.product(dt, dt):
779 for sg1, sg2 in itertools.product((+1, -1), (+1, -1)):
780 fmt = 'op: %s, dt1: %s, dt2: %s, sg1: %s, sg2: %s'
781 msg = fmt % (op.__name__, dt1, dt2, sg1, sg2)
782 a = np.array(sg1 * 78 * 6e-8, dtype=dt1)
783 b = np.array(sg2 * 6e-8, dtype=dt2)
784 div, rem = op(a, b)
785 # Equal assertion should hold when fmod is used
786 assert_equal(div * b + rem, a, err_msg=msg)
787 if sg2 == -1:
788 assert_(b < rem <= 0, msg)
789 else:
790 assert_(b > rem >= 0, msg)
791
792 @pytest.mark.skipif(IS_WASM, reason="fp errors don't work in wasm")
793 @pytest.mark.xfail(sys.platform.startswith("darwin"),
794 reason="MacOS seems to not give the correct 'invalid' warning for "
795 "`fmod`. Hopefully, others always do.")
796 @pytest.mark.parametrize('dtype', np.typecodes['Float'])
797 def test_float_divmod_errors(self, dtype):
798 # Check valid errors raised for divmod and remainder
799 fzero = np.array(0.0, dtype=dtype)
800 fone = np.array(1.0, dtype=dtype)
801 finf = np.array(np.inf, dtype=dtype)
802 fnan = np.array(np.nan, dtype=dtype)
803 # since divmod is combination of both remainder and divide
804 # ops it will set both dividebyzero and invalid flags
805 with np.errstate(divide='raise', invalid='ignore'):
806 assert_raises(FloatingPointError, np.divmod, fone, fzero)
807 with np.errstate(divide='ignore', invalid='raise'):
808 assert_raises(FloatingPointError, np.divmod, fone, fzero)
809 with np.errstate(invalid='raise'):
810 assert_raises(FloatingPointError, np.divmod, fzero, fzero)
811 with np.errstate(invalid='raise'):
812 assert_raises(FloatingPointError, np.divmod, finf, finf)
813 with np.errstate(divide='ignore', invalid='raise'):
814 assert_raises(FloatingPointError, np.divmod, finf, fzero)
815 with np.errstate(divide='raise', invalid='ignore'):
816 # inf / 0 does not set any flags, only the modulo creates a NaN
817 np.divmod(finf, fzero)
818
819 @pytest.mark.skipif(hasattr(np.__config__, "blas_ssl2_info"),
820 reason="gh-22982")
821 @pytest.mark.skipif(IS_WASM, reason="fp errors don't work in wasm")
822 @pytest.mark.xfail(sys.platform.startswith("darwin"),
823 reason="MacOS seems to not give the correct 'invalid' warning for "
824 "`fmod`. Hopefully, others always do.")
825 @pytest.mark.parametrize('dtype', np.typecodes['Float'])
826 @pytest.mark.parametrize('fn', [np.fmod, np.remainder])
827 def test_float_remainder_errors(self, dtype, fn):
828 fzero = np.array(0.0, dtype=dtype)
829 fone = np.array(1.0, dtype=dtype)
830 finf = np.array(np.inf, dtype=dtype)
831 fnan = np.array(np.nan, dtype=dtype)
832
833 # The following already contain a NaN and should not warn.
834 with np.errstate(all='raise'):
835 with pytest.raises(FloatingPointError,
836 match="invalid value"):
837 fn(fone, fzero)
838 fn(fnan, fzero)
839 fn(fzero, fnan)
840 fn(fone, fnan)
841 fn(fnan, fone)
842
843 @pytest.mark.skipif(IS_WASM, reason="fp errors don't work in wasm")
844 def test_float_remainder_overflow(self):
845 a = np.finfo(np.float64).tiny
846 with np.errstate(over='ignore', invalid='ignore'):
847 div, mod = np.divmod(4, a)
848 np.isinf(div)
849 assert_(mod == 0)
850 with np.errstate(over='raise', invalid='ignore'):
851 assert_raises(FloatingPointError, np.divmod, 4, a)
852 with np.errstate(invalid='raise', over='ignore'):
853 assert_raises(FloatingPointError, np.divmod, 4, a)
854
855 def test_float_divmod_corner_cases(self):
856 # check nan cases
857 for dt in np.typecodes['Float']:
858 fnan = np.array(np.nan, dtype=dt)
859 fone = np.array(1.0, dtype=dt)
860 fzer = np.array(0.0, dtype=dt)
861 finf = np.array(np.inf, dtype=dt)
862 with warnings.catch_warnings():
863 warnings.filterwarnings('ignore', "invalid value encountered in divmod", RuntimeWarning)
864 warnings.filterwarnings('ignore', "divide by zero encountered in divmod", RuntimeWarning)
865 div, rem = np.divmod(fone, fzer)
866 assert np.isinf(div), f'dt: {dt}, div: {rem}'
867 assert np.isnan(rem), f'dt: {dt}, rem: {rem}'
868 div, rem = np.divmod(fzer, fzer)
869 assert np.isnan(rem), f'dt: {dt}, rem: {rem}'
870 assert_(np.isnan(div)), f'dt: {dt}, rem: {rem}'
871 div, rem = np.divmod(finf, finf)
872 assert np.isnan(div), f'dt: {dt}, rem: {rem}'
873 assert np.isnan(rem), f'dt: {dt}, rem: {rem}'
874 div, rem = np.divmod(finf, fzer)
875 assert np.isinf(div), f'dt: {dt}, rem: {rem}'
876 assert np.isnan(rem), f'dt: {dt}, rem: {rem}'
877 div, rem = np.divmod(fnan, fone)
878 assert np.isnan(rem), f"dt: {dt}, rem: {rem}"
879 assert np.isnan(div), f"dt: {dt}, rem: {rem}"
880 div, rem = np.divmod(fone, fnan)
881 assert np.isnan(rem), f"dt: {dt}, rem: {rem}"
882 assert np.isnan(div), f"dt: {dt}, rem: {rem}"
883 div, rem = np.divmod(fnan, fzer)
884 assert np.isnan(rem), f"dt: {dt}, rem: {rem}"
885 assert np.isnan(div), f"dt: {dt}, rem: {rem}"
886
887 def test_float_remainder_corner_cases(self):
888 # Check remainder magnitude.
889 for dt in np.typecodes['Float']:
890 fone = np.array(1.0, dtype=dt)
891 fzer = np.array(0.0, dtype=dt)
892 fnan = np.array(np.nan, dtype=dt)
893 b = np.array(1.0, dtype=dt)
894 a = np.nextafter(np.array(0.0, dtype=dt), -b)
895 rem = np.remainder(a, b)
896 assert_(rem <= b, f'dt: {dt}')
897 rem = np.remainder(-a, -b)
898 assert_(rem >= -b, f'dt: {dt}')
899
900 # Check nans, inf
901 with warnings.catch_warnings():
902 warnings.filterwarnings('ignore', "invalid value encountered in remainder", RuntimeWarning)
903 warnings.filterwarnings('ignore', "invalid value encountered in fmod", RuntimeWarning)
904 for dt in np.typecodes['Float']:
905 fone = np.array(1.0, dtype=dt)
906 fzer = np.array(0.0, dtype=dt)
907 finf = np.array(np.inf, dtype=dt)
908 fnan = np.array(np.nan, dtype=dt)
909 rem = np.remainder(fone, fzer)
910 assert_(np.isnan(rem), f'dt: {dt}, rem: {rem}')
911 # MSVC 2008 returns NaN here, so disable the check.
912 #rem = np.remainder(fone, finf)
913 #assert_(rem == fone, 'dt: %s, rem: %s' % (dt, rem))
914 rem = np.remainder(finf, fone)
915 fmod = np.fmod(finf, fone)
916 assert_(np.isnan(fmod), f'dt: {dt}, fmod: {fmod}')
917 assert_(np.isnan(rem), f'dt: {dt}, rem: {rem}')
918 rem = np.remainder(finf, finf)
919 fmod = np.fmod(finf, fone)
920 assert_(np.isnan(rem), f'dt: {dt}, rem: {rem}')
921 assert_(np.isnan(fmod), f'dt: {dt}, fmod: {fmod}')
922 rem = np.remainder(finf, fzer)
923 fmod = np.fmod(finf, fzer)
924 assert_(np.isnan(rem), f'dt: {dt}, rem: {rem}')
925 assert_(np.isnan(fmod), f'dt: {dt}, fmod: {fmod}')
926 rem = np.remainder(fone, fnan)
927 fmod = np.fmod(fone, fnan)
928 assert_(np.isnan(rem), f'dt: {dt}, rem: {rem}')
929 assert_(np.isnan(fmod), f'dt: {dt}, fmod: {fmod}')
930 rem = np.remainder(fnan, fzer)
931 fmod = np.fmod(fnan, fzer)
932 assert_(np.isnan(rem), f'dt: {dt}, rem: {rem}')
933 assert_(np.isnan(fmod), f'dt: {dt}, fmod: {rem}')
934 rem = np.remainder(fnan, fone)
935 fmod = np.fmod(fnan, fone)
936 assert_(np.isnan(rem), f'dt: {dt}, rem: {rem}')
937 assert_(np.isnan(fmod), f'dt: {dt}, fmod: {rem}')
938
939
940class TestDivisionIntegerOverflowsAndDivideByZero:
941 result_type = namedtuple('result_type',
942 ['nocast', 'casted'])
943 helper_lambdas = {
944 'zero': lambda dtype: 0,
945 'min': lambda dtype: np.iinfo(dtype).min,
946 'neg_min': lambda dtype: -np.iinfo(dtype).min,
947 'min-zero': lambda dtype: (np.iinfo(dtype).min, 0),
948 'neg_min-zero': lambda dtype: (-np.iinfo(dtype).min, 0),
949 }
950 overflow_results = {
951 np.remainder: result_type(
952 helper_lambdas['zero'], helper_lambdas['zero']),
953 np.fmod: result_type(
954 helper_lambdas['zero'], helper_lambdas['zero']),
955 operator.mod: result_type(
956 helper_lambdas['zero'], helper_lambdas['zero']),
957 operator.floordiv: result_type(
958 helper_lambdas['min'], helper_lambdas['neg_min']),
959 np.floor_divide: result_type(
960 helper_lambdas['min'], helper_lambdas['neg_min']),
961 np.divmod: result_type(
962 helper_lambdas['min-zero'], helper_lambdas['neg_min-zero'])
963 }
964
965 @pytest.mark.skipif(IS_WASM, reason="fp errors don't work in wasm")
966 @pytest.mark.parametrize("dtype", np.typecodes["Integer"])
967 def test_signed_division_overflow(self, dtype):
968 to_check = interesting_binop_operands(np.iinfo(dtype).min, -1, dtype)
969 for op1, op2, extractor, operand_identifier in to_check:
970 with pytest.warns(RuntimeWarning, match="overflow encountered"):
971 res = op1 // op2
972
973 assert res.dtype == op1.dtype
974 assert extractor(res) == np.iinfo(op1.dtype).min
975
976 # Remainder is well defined though, and does not warn:
977 res = op1 % op2
978 assert res.dtype == op1.dtype
979 assert extractor(res) == 0
980 # Check fmod as well:
981 res = np.fmod(op1, op2)
982 assert extractor(res) == 0
983
984 # Divmod warns for the division part:
985 with pytest.warns(RuntimeWarning, match="overflow encountered"):
986 res1, res2 = np.divmod(op1, op2)
987
988 assert res1.dtype == res2.dtype == op1.dtype
989 assert extractor(res1) == np.iinfo(op1.dtype).min
990 assert extractor(res2) == 0
991
992 @pytest.mark.skipif(IS_WASM, reason="fp errors don't work in wasm")
993 @pytest.mark.parametrize("dtype", np.typecodes["AllInteger"])
994 def test_divide_by_zero(self, dtype):
995 # Note that the return value cannot be well defined here, but NumPy
996 # currently uses 0 consistently. This could be changed.
997 to_check = interesting_binop_operands(1, 0, dtype)
998 for op1, op2, extractor, operand_identifier in to_check:
999 with pytest.warns(RuntimeWarning, match="divide by zero"):
1000 res = op1 // op2
1001
1002 assert res.dtype == op1.dtype
1003 assert extractor(res) == 0
1004
1005 with pytest.warns(RuntimeWarning, match="divide by zero"):
1006 res1, res2 = np.divmod(op1, op2)
1007
1008 assert res1.dtype == res2.dtype == op1.dtype
1009 assert extractor(res1) == 0
1010 assert extractor(res2) == 0
1011
1012 @pytest.mark.skipif(IS_WASM, reason="fp errors don't work in wasm")
1013 @pytest.mark.parametrize("dividend_dtype", sctypes['int'])
1014 @pytest.mark.parametrize("divisor_dtype", sctypes['int'])
1015 @pytest.mark.parametrize("operation",
1016 [np.remainder, np.fmod, np.divmod, np.floor_divide,
1017 operator.mod, operator.floordiv])
1018 @np.errstate(divide='warn', over='warn')
1019 def test_overflows(self, dividend_dtype, divisor_dtype, operation):
1020 # SIMD tries to perform the operation on as many elements as possible
1021 # that is a multiple of the register's size. We resort to the
1022 # default implementation for the leftover elements.
1023 # We try to cover all paths here.
1024 arrays = [np.array([np.iinfo(dividend_dtype).min] * i,
1025 dtype=dividend_dtype) for i in range(1, 129)]
1026 divisor = np.array([-1], dtype=divisor_dtype)
1027 # If dividend is a larger type than the divisor (`else` case),
1028 # then, result will be a larger type than dividend and will not
1029 # result in an overflow for `divmod` and `floor_divide`.
1030 if np.dtype(dividend_dtype).itemsize >= np.dtype(
1031 divisor_dtype).itemsize and operation in (
1032 np.divmod, np.floor_divide, operator.floordiv):
1033 with pytest.warns(
1034 RuntimeWarning,
1035 match="overflow encountered in"):
1036 result = operation(
1037 dividend_dtype(np.iinfo(dividend_dtype).min),
1038 divisor_dtype(-1)
1039 )
1040 assert result == self.overflow_results[operation].nocast(
1041 dividend_dtype)
1042
1043 # Arrays
1044 for a in arrays:
1045 # In case of divmod, we need to flatten the result
1046 # column first as we get a column vector of quotient and
1047 # remainder and a normal flatten of the expected result.
1048 with pytest.warns(
1049 RuntimeWarning,
1050 match="overflow encountered in"):
1051 result = np.array(operation(a, divisor)).flatten('f')
1052 expected_array = np.array(
1053 [self.overflow_results[operation].nocast(
1054 dividend_dtype)] * len(a)).flatten()
1055 assert_array_equal(result, expected_array)
1056 else:
1057 # Scalars
1058 result = operation(
1059 dividend_dtype(np.iinfo(dividend_dtype).min),
1060 divisor_dtype(-1)
1061 )
1062 assert result == self.overflow_results[operation].casted(
1063 dividend_dtype)
1064
1065 # Arrays
1066 for a in arrays:
1067 # See above comment on flatten
1068 result = np.array(operation(a, divisor)).flatten('f')
1069 expected_array = np.array(
1070 [self.overflow_results[operation].casted(
1071 dividend_dtype)] * len(a)).flatten()
1072 assert_array_equal(result, expected_array)
1073
1074
1075class TestCbrt:
1076 def test_cbrt_scalar(self):
1077 assert_almost_equal((np.cbrt(np.float32(-2.5)**3)), -2.5)
1078
1079 def test_cbrt(self):
1080 x = np.array([1., 2., -3., np.inf, -np.inf])
1081 assert_almost_equal(np.cbrt(x**3), x)
1082
1083 assert_(np.isnan(np.cbrt(np.nan)))
1084 assert_equal(np.cbrt(np.inf), np.inf)
1085 assert_equal(np.cbrt(-np.inf), -np.inf)
1086
1087
1088class TestPower:
1089 def test_power_float(self):
1090 x = np.array([1., 2., 3.])
1091 assert_equal(x**0, [1., 1., 1.])
1092 assert_equal(x**1, x)
1093 assert_equal(x**2, [1., 4., 9.])
1094 y = x.copy()
1095 y **= 2
1096 assert_equal(y, [1., 4., 9.])
1097 assert_almost_equal(x**(-1), [1., 0.5, 1. / 3])
1098 assert_almost_equal(x**(0.5), [1., ncu.sqrt(2), ncu.sqrt(3)])
1099
1100 for out, inp, msg in _gen_alignment_data(dtype=np.float32,
1101 type='unary',
1102 max_size=11):
1103 exp = [ncu.sqrt(i) for i in inp]
1104 assert_almost_equal(inp**(0.5), exp, err_msg=msg)
1105 np.sqrt(inp, out=out)
1106 assert_equal(out, exp, err_msg=msg)
1107
1108 for out, inp, msg in _gen_alignment_data(dtype=np.float64,
1109 type='unary',
1110 max_size=7):
1111 exp = [ncu.sqrt(i) for i in inp]
1112 assert_almost_equal(inp**(0.5), exp, err_msg=msg)
1113 np.sqrt(inp, out=out)
1114 assert_equal(out, exp, err_msg=msg)
1115
1116 def test_power_complex(self):
1117 x = np.array([1 + 2j, 2 + 3j, 3 + 4j])
1118 assert_equal(x**0, [1., 1., 1.])
1119 assert_equal(x**1, x)
1120 assert_almost_equal(x**2, [-3 + 4j, -5 + 12j, -7 + 24j])
1121 assert_almost_equal(x**3, [(1 + 2j)**3, (2 + 3j)**3, (3 + 4j)**3])
1122 assert_almost_equal(x**4, [(1 + 2j)**4, (2 + 3j)**4, (3 + 4j)**4])
1123 assert_almost_equal(x**(-1), [1 / (1 + 2j), 1 / (2 + 3j), 1 / (3 + 4j)])
1124 assert_almost_equal(x**(-2), [1 / (1 + 2j)**2, 1 / (2 + 3j)**2, 1 / (3 + 4j)**2])
1125 assert_almost_equal(x**(-3), [(-11 + 2j) / 125, (-46 - 9j) / 2197,
1126 (-117 - 44j) / 15625])
1127 assert_almost_equal(x**(0.5), [ncu.sqrt(1 + 2j), ncu.sqrt(2 + 3j),
1128 ncu.sqrt(3 + 4j)])
1129 norm = 1. / ((x**14)[0])
1130 assert_almost_equal(x**14 * norm,
1131 [i * norm for i in [-76443 + 16124j, 23161315 + 58317492j,
1132 5583548873 + 2465133864j]])
1133
1134 # Ticket #836
1135 def assert_complex_equal(x, y):
1136 assert_array_equal(x.real, y.real)
1137 assert_array_equal(x.imag, y.imag)
1138
1139 for z in [complex(0, np.inf), complex(1, np.inf)]:
1140 z = np.array([z], dtype=np.complex128)
1141 with np.errstate(invalid="ignore"):
1142 assert_complex_equal(z**1, z)
1143 assert_complex_equal(z**2, z * z)
1144 assert_complex_equal(z**3, z * z * z)
1145
1146 def test_power_zero(self):
1147 # ticket #1271
1148 zero = np.array([0j])
1149 one = np.array([1 + 0j])
1150 cnan = np.array([complex(np.nan, np.nan)])
1151 # FIXME cinf not tested.
1152 #cinf = np.array([complex(np.inf, 0)])
1153
1154 def assert_complex_equal(x, y):
1155 x, y = np.asarray(x), np.asarray(y)
1156 assert_array_equal(x.real, y.real)
1157 assert_array_equal(x.imag, y.imag)
1158
1159 # positive powers
1160 for p in [0.33, 0.5, 1, 1.5, 2, 3, 4, 5, 6.6]:
1161 assert_complex_equal(np.power(zero, p), zero)
1162
1163 # zero power
1164 assert_complex_equal(np.power(zero, 0), one)
1165 with np.errstate(invalid="ignore"):
1166 assert_complex_equal(np.power(zero, 0 + 1j), cnan)
1167
1168 # negative power
1169 for p in [0.33, 0.5, 1, 1.5, 2, 3, 4, 5, 6.6]:
1170 assert_complex_equal(np.power(zero, -p), cnan)
1171 assert_complex_equal(np.power(zero, -1 + 0.2j), cnan)
1172
1173 @pytest.mark.skipif(IS_WASM, reason="fp errors don't work in wasm")
1174 def test_zero_power_nonzero(self):
1175 # Testing 0^{Non-zero} issue 18378
1176 zero = np.array([0.0 + 0.0j])
1177 cnan = np.array([complex(np.nan, np.nan)])
1178
1179 def assert_complex_equal(x, y):
1180 assert_array_equal(x.real, y.real)
1181 assert_array_equal(x.imag, y.imag)
1182
1183 # Complex powers with positive real part will not generate a warning
1184 assert_complex_equal(np.power(zero, 1 + 4j), zero)
1185 assert_complex_equal(np.power(zero, 2 - 3j), zero)
1186 # Testing zero values when real part is greater than zero
1187 assert_complex_equal(np.power(zero, 1 + 1j), zero)
1188 assert_complex_equal(np.power(zero, 1 + 0j), zero)
1189 assert_complex_equal(np.power(zero, 1 - 1j), zero)
1190 # Complex powers will negative real part or 0 (provided imaginary
1191 # part is not zero) will generate a NAN and hence a RUNTIME warning
1192 with pytest.warns(expected_warning=RuntimeWarning) as r:
1193 assert_complex_equal(np.power(zero, -1 + 1j), cnan)
1194 assert_complex_equal(np.power(zero, -2 - 3j), cnan)
1195 assert_complex_equal(np.power(zero, -7 + 0j), cnan)
1196 assert_complex_equal(np.power(zero, 0 + 1j), cnan)
1197 assert_complex_equal(np.power(zero, 0 - 1j), cnan)
1198 assert len(r) == 5
1199
1200 def test_fast_power(self):
