Skip to content

BUG: integers to a negative integer powers should error. #8127

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Oct 20, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 12 additions & 7 deletions doc/release/1.12.0-notes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -73,18 +73,24 @@ DeprecationWarning to error
* Non-integers used as index values raise ``TypeError``,
e.g., in ``reshape``, ``take``, and specifying reduce axis.

``power`` and ``**`` raise errors for integer to negative integer powers
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The previous behavior was

* zero to negative integer powers returned least integral value.
* 1, -1 to negative integer powers returned correct values
* all remaining integers returned zero when raised to negative integer powers.

All of these cases now raise a ``ValueError``. It was felt that a simple rule
was the best way to go rather than have special exceptions for the units. If
you need negative powers, use an inexact type.

Relaxed stride checking is the default
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

This will have some impact on code that assumed that ``F_CONTIGUOUS`` and
``C_CONTIGUOUS`` were mutually exclusive and could be set to determine the
default order for arrays that are now both.

``MaskedArray`` takes view of data **and** mask when slicing
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
XXX


``np.percentile`` 'midpoint' interpolation method fixed for exact indices
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
'midpoint' interpolator now gives the same result as 'lower' and 'higher' when
Expand All @@ -93,7 +99,6 @@ the two coincide. Previous behavior of 'lower' + 0.5 is fixed.

``keepdims`` kwarg is passed through to user-class methods
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

numpy functions that take a ``keepdims`` kwarg now pass the value
through to the corresponding methods on ndarray sub-classes. Previously the
``keepdims`` keyword would be silently dropped. These functions now have
Expand Down
19 changes: 13 additions & 6 deletions numpy/core/src/umath/loops.c.src
Original file line number Diff line number Diff line change
Expand Up @@ -787,6 +787,7 @@ BOOL__ones_like(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UN
* npy_long, npy_ulong, npy_longlong, npy_ulonglong#
* #ftype = npy_float, npy_float, npy_float, npy_float, npy_double, npy_double,
* npy_double, npy_double, npy_double, npy_double#
* #SIGNED = 1, 0, 1, 0, 1, 0, 1, 0, 1, 0#
*/

#define @TYPE@_floor_divide @TYPE@_divide
Expand Down Expand Up @@ -959,16 +960,22 @@ NPY_NO_EXPORT void
@type@ in2 = *(@type@ *)ip2;
@type@ out;

if (in2 == 0) {
*((@type@ *)op1) = 1;
continue;
#if @SIGNED@
if (in2 < 0) {
NPY_ALLOW_C_API_DEF
NPY_ALLOW_C_API;
PyErr_SetString(PyExc_ValueError,
"Integers to negative integer powers are not allowed.");
NPY_DISABLE_C_API;
return;
}
if (in1 == 1) {
#endif
if (in2 == 0) {
*((@type@ *)op1) = 1;
continue;
}
if (in2 < 0 || in1 == 0) {
*((@type@ *)op1) = 0;
if (in1 == 1) {
*((@type@ *)op1) = 1;
continue;
}

Expand Down
13 changes: 0 additions & 13 deletions numpy/core/tests/test_regression.py
Original file line number Diff line number Diff line change
Expand Up @@ -1242,19 +1242,6 @@ def test_array_ndmin_overflow(self):
"Ticket #947."
self.assertRaises(ValueError, lambda: np.array([1], ndmin=33))

def test_errobj_reference_leak(self, level=rlevel):
# Ticket #955
with np.errstate(all="ignore"):
z = int(0)
p = np.int32(-1)

gc.collect()
n_before = len(gc.get_objects())
z**p # this shouldn't leak a reference to errobj
gc.collect()
n_after = len(gc.get_objects())
assert_(n_before >= n_after, (n_before, n_after))

def test_void_scalar_with_titles(self, level=rlevel):
# No ticket
data = [('john', 4), ('mary', 5)]
Expand Down
39 changes: 33 additions & 6 deletions numpy/core/tests/test_umath.py
Original file line number Diff line number Diff line change
Expand Up @@ -426,16 +426,43 @@ def test_fast_power(self):

def test_integer_power(self):
a = np.array([15, 15], 'i8')
b = a ** a
b = np.power(a, a)
assert_equal(b, [437893890380859375, 437893890380859375])

def test_integer_power_with_zero_exponent(self):
arr = np.arange(-10, 10)
assert_equal(np.power(arr, 0), np.ones_like(arr))
def test_integer_power_with_integer_zero_exponent(self):
dtypes = np.typecodes['Integer']
for dt in dtypes:
arr = np.arange(-10, 10, dtype=dt)
assert_equal(np.power(arr, 0), np.ones_like(arr))

dtypes = np.typecodes['UnsignedInteger']
for dt in dtypes:
arr = np.arange(10, dtype=dt)
assert_equal(np.power(arr, 0), np.ones_like(arr))

def test_integer_power_of_1(self):
arr = np.arange(-10, 10)
assert_equal(np.power(1, arr), np.ones_like(arr))
dtypes = np.typecodes['AllInteger']
for dt in dtypes:
arr = np.arange(10, dtype=dt)
assert_equal(np.power(1, arr), np.ones_like(arr))

def test_integer_power_of_zero(self):
dtypes = np.typecodes['AllInteger']
for dt in dtypes:
arr = np.arange(1, 10, dtype=dt)
assert_equal(np.power(0, arr), np.zeros_like(arr))

def test_integer_to_negative_power(self):
dtypes = np.typecodes['Integer']
for dt in dtypes:
a = np.array([0, 1, 2, 3], dtype=dt)
b = np.array([0, 1, 2, -3], dtype=dt)
one = np.array(1, dtype=dt)
minusone = np.array(-1, dtype=dt)
assert_raises(ValueError, np.power, a, b)
assert_raises(ValueError, np.power, a, minusone)
assert_raises(ValueError, np.power, one, b)
assert_raises(ValueError, np.power, one, minusone)


class TestLog2(TestCase):
Expand Down