summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEric Moore <ewm@redtetrahedron.org>2016-04-01 14:55:02 -0400
committerEric Moore <ewm@redtetrahedron.org>2016-03-31 23:58:36 -0400
commite7ddb392728260801a8ae39ef36b0bbf3abe5604 (patch)
treecb51699ae47e56871dee8a553fbe2430fd0a8ca9
parent2af06c804931aae4b30bb3349bc60271b0b65381 (diff)
downloadnumpy-e7ddb392728260801a8ae39ef36b0bbf3abe5604.tar.gz
BUG: don't use pow for integer power ufunc loops.
Fixes gh-7405.
-rw-r--r--numpy/core/src/umath/loops.c.src26
-rw-r--r--numpy/core/tests/test_umath.py5
2 files changed, 28 insertions, 3 deletions
diff --git a/numpy/core/src/umath/loops.c.src b/numpy/core/src/umath/loops.c.src
index 0d9806f5d..a829e4104 100644
--- a/numpy/core/src/umath/loops.c.src
+++ b/numpy/core/src/umath/loops.c.src
@@ -913,9 +913,29 @@ NPY_NO_EXPORT void
@TYPE@_power(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func))
{
BINARY_LOOP {
- const @ftype@ in1 = (@ftype@)*(@type@ *)ip1;
- const @ftype@ in2 = (@ftype@)*(@type@ *)ip2;
- *((@type@ *)op1) = (@type@) pow(in1, in2);
+ @type@ in1 = *(@type@ *)ip1;
+ @type@ in2 = *(@type@ *)ip2;
+ @type@ out;
+
+ if (in2 < 0 || in1 == 0) {
+ *((@type@ *)op1) = 0;
+ continue;
+ }
+ if (in2 == 0) {
+ *((@type@ *)op1) = 1;
+ continue;
+ }
+
+ out = in2 & 1 ? in1 : 1;
+ in2 >>= 1;
+ while (in2 > 0) {
+ in1 *= in1;
+ if (in2 & 1) {
+ out *= in1;
+ }
+ in2 >>= 1;
+ }
+ *((@type@ *) op1) = out;
}
}
diff --git a/numpy/core/tests/test_umath.py b/numpy/core/tests/test_umath.py
index f0f664a6f..d3d89f086 100644
--- a/numpy/core/tests/test_umath.py
+++ b/numpy/core/tests/test_umath.py
@@ -425,6 +425,11 @@ class TestPower(TestCase):
res = x ** np.array([[[2]]])
assert_equal(res.shape, (1, 1, 3))
+ def test_integer_power(self):
+ a = np.array([15, 15], 'i8')
+ b = a ** a
+ assert_equal(b, [437893890380859375, 437893890380859375])
+
class TestLog2(TestCase):
def test_log2_values(self):