summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--benchmarks/benchmarks/bench_overrides.py10
-rw-r--r--numpy/core/code_generators/generate_umath.py2
-rw-r--r--numpy/core/src/umath/loops.c.src25
-rw-r--r--numpy/core/src/umath/loops.h.src3
-rw-r--r--numpy/core/src/umath/ufunc_type_resolution.c9
-rw-r--r--numpy/core/tests/test_datetime.py82
-rw-r--r--numpy/core/tests/test_multiarray.py4
-rw-r--r--numpy/distutils/fcompiler/environment.py15
-rw-r--r--numpy/distutils/tests/test_fcompiler.py41
9 files changed, 181 insertions, 10 deletions
diff --git a/benchmarks/benchmarks/bench_overrides.py b/benchmarks/benchmarks/bench_overrides.py
index b42c5d185..58572d07d 100644
--- a/benchmarks/benchmarks/bench_overrides.py
+++ b/benchmarks/benchmarks/bench_overrides.py
@@ -2,7 +2,15 @@ from __future__ import absolute_import, division, print_function
from .common import Benchmark
-from numpy.core.overrides import array_function_dispatch
+try:
+ from numpy.core.overrides import array_function_dispatch
+except ImportError:
+ # Don't fail at import time with old Numpy versions
+ def array_function_dispatch(*args, **kwargs):
+ def wrap(*args, **kwargs):
+ return None
+ return wrap
+
import numpy as np
diff --git a/numpy/core/code_generators/generate_umath.py b/numpy/core/code_generators/generate_umath.py
index f5ee02c42..108fff631 100644
--- a/numpy/core/code_generators/generate_umath.py
+++ b/numpy/core/code_generators/generate_umath.py
@@ -315,7 +315,7 @@ defdict = {
TD(intfltcmplx),
[TypeDescription('m', FullTypeDescr, 'mq', 'm'),
TypeDescription('m', FullTypeDescr, 'md', 'm'),
- #TypeDescription('m', FullTypeDescr, 'mm', 'd'),
+ TypeDescription('m', FullTypeDescr, 'mm', 'q'),
],
TD(O, f='PyNumber_FloorDivide'),
),
diff --git a/numpy/core/src/umath/loops.c.src b/numpy/core/src/umath/loops.c.src
index ae3ece77b..53afa817b 100644
--- a/numpy/core/src/umath/loops.c.src
+++ b/numpy/core/src/umath/loops.c.src
@@ -1619,6 +1619,31 @@ TIMEDELTA_mm_m_remainder(char **args, npy_intp *dimensions, npy_intp *steps, voi
}
}
+NPY_NO_EXPORT void
+TIMEDELTA_mm_q_floor_divide(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func))
+{
+ BINARY_LOOP {
+ const npy_timedelta in1 = *(npy_timedelta *)ip1;
+ const npy_timedelta in2 = *(npy_timedelta *)ip2;
+ if (in1 == NPY_DATETIME_NAT || in2 == NPY_DATETIME_NAT) {
+ npy_set_floatstatus_invalid();
+ *((npy_timedelta *)op1) = 0;
+ }
+ else if (in2 == 0) {
+ npy_set_floatstatus_divbyzero();
+ *((npy_timedelta *)op1) = 0;
+ }
+ else {
+ if (((in1 > 0) != (in2 > 0)) && (in1 % in2 != 0)) {
+ *((npy_timedelta *)op1) = in1/in2 - 1;
+ }
+ else {
+ *((npy_timedelta *)op1) = in1/in2;
+ }
+ }
+ }
+}
+
/*
*****************************************************************************
** FLOAT LOOPS **
diff --git a/numpy/core/src/umath/loops.h.src b/numpy/core/src/umath/loops.h.src
index 9b6327308..3c908121e 100644
--- a/numpy/core/src/umath/loops.h.src
+++ b/numpy/core/src/umath/loops.h.src
@@ -474,6 +474,9 @@ NPY_NO_EXPORT void
TIMEDELTA_mm_d_divide(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func));
NPY_NO_EXPORT void
+TIMEDELTA_mm_q_floor_divide(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func));
+
+NPY_NO_EXPORT void
TIMEDELTA_mm_m_remainder(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func));
/* Special case equivalents to above functions */
diff --git a/numpy/core/src/umath/ufunc_type_resolution.c b/numpy/core/src/umath/ufunc_type_resolution.c
index ec60d9cfd..3cf507258 100644
--- a/numpy/core/src/umath/ufunc_type_resolution.c
+++ b/numpy/core/src/umath/ufunc_type_resolution.c
@@ -1114,7 +1114,16 @@ PyUFunc_DivisionTypeResolver(PyUFuncObject *ufunc,
}
out_dtypes[1] = out_dtypes[0];
Py_INCREF(out_dtypes[1]);
+
+ /*
+ * TODO: split function into truediv and floordiv resolvers
+ */
+ if (strcmp(ufunc->name, "floor_divide") == 0) {
+ out_dtypes[2] = PyArray_DescrFromType(NPY_LONGLONG);
+ }
+ else {
out_dtypes[2] = PyArray_DescrFromType(NPY_DOUBLE);
+ }
if (out_dtypes[2] == NULL) {
Py_DECREF(out_dtypes[0]);
out_dtypes[0] = NULL;
diff --git a/numpy/core/tests/test_datetime.py b/numpy/core/tests/test_datetime.py
index b2ce0402a..cb7555a34 100644
--- a/numpy/core/tests/test_datetime.py
+++ b/numpy/core/tests/test_datetime.py
@@ -1081,6 +1081,86 @@ class TestDateTime(object):
check(np.timedelta64(0), f, nat)
check(nat, f, nat)
+ @pytest.mark.parametrize("op1, op2, exp", [
+ # m8 same units round down
+ (np.timedelta64(7, 's'),
+ np.timedelta64(4, 's'),
+ 1),
+ # m8 same units round down with negative
+ (np.timedelta64(7, 's'),
+ np.timedelta64(-4, 's'),
+ -2),
+ # m8 same units negative no round down
+ (np.timedelta64(8, 's'),
+ np.timedelta64(-4, 's'),
+ -2),
+ # m8 different units
+ (np.timedelta64(1, 'm'),
+ np.timedelta64(31, 's'),
+ 1),
+ # m8 generic units
+ (np.timedelta64(1890),
+ np.timedelta64(31),
+ 60),
+ # Y // M works
+ (np.timedelta64(2, 'Y'),
+ np.timedelta64('13', 'M'),
+ 1),
+ # handle 1D arrays
+ (np.array([1, 2, 3], dtype='m8'),
+ np.array([2], dtype='m8'),
+ np.array([0, 1, 1], dtype=np.int64)),
+ ])
+ def test_timedelta_floor_divide(self, op1, op2, exp):
+ assert_equal(op1 // op2, exp)
+
+ @pytest.mark.parametrize("op1, op2", [
+ # div by 0
+ (np.timedelta64(10, 'us'),
+ np.timedelta64(0, 'us')),
+ # div with NaT
+ (np.timedelta64('NaT'),
+ np.timedelta64(50, 'us')),
+ # special case for int64 min
+ # in integer floor division
+ (np.timedelta64(np.iinfo(np.int64).min),
+ np.timedelta64(-1)),
+ ])
+ def test_timedelta_floor_div_warnings(self, op1, op2):
+ with assert_warns(RuntimeWarning):
+ actual = op1 // op2
+ assert_equal(actual, 0)
+ assert_equal(actual.dtype, np.int64)
+
+ @pytest.mark.parametrize("val1, val2", [
+ # the smallest integer that can't be represented
+ # exactly in a double should be preserved if we avoid
+ # casting to double in floordiv operation
+ (9007199254740993, 1),
+ # stress the alternate floordiv code path where
+ # operand signs don't match and remainder isn't 0
+ (9007199254740999, -2),
+ ])
+ def test_timedelta_floor_div_precision(self, val1, val2):
+ op1 = np.timedelta64(val1)
+ op2 = np.timedelta64(val2)
+ actual = op1 // op2
+ # Python reference integer floor
+ expected = val1 // val2
+ assert_equal(actual, expected)
+
+ @pytest.mark.parametrize("val1, val2", [
+ # years and months sometimes can't be unambiguously
+ # divided for floor division operation
+ (np.timedelta64(7, 'Y'),
+ np.timedelta64(3, 's')),
+ (np.timedelta64(7, 'M'),
+ np.timedelta64(1, 'D')),
+ ])
+ def test_timedelta_floor_div_error(self, val1, val2):
+ with assert_raises_regex(TypeError, "common metadata divisor"):
+ val1 // val2
+
def test_datetime_divide(self):
for dta, tda, tdb, tdc, tdd in \
[
@@ -1111,8 +1191,6 @@ class TestDateTime(object):
assert_equal(tda / tdd, 60.0)
assert_equal(tdd / tda, 1.0 / 60.0)
- # m8 // m8
- assert_raises(TypeError, np.floor_divide, tda, tdb)
# int / m8
assert_raises(TypeError, np.divide, 2, tdb)
# float / m8
diff --git a/numpy/core/tests/test_multiarray.py b/numpy/core/tests/test_multiarray.py
index 951c01c6d..91f4526bd 100644
--- a/numpy/core/tests/test_multiarray.py
+++ b/numpy/core/tests/test_multiarray.py
@@ -8000,10 +8000,10 @@ class TestAlignment(object):
raise ValueError()
def test_various_alignments(self):
- for align in [1, 2, 3, 4, 8, 16, 32, 64, None]:
+ for align in [1, 2, 3, 4, 8, 12, 16, 32, 64, None]:
for n in [0, 1, 3, 11]:
for order in ["C", "F", None]:
- for dtype in np.typecodes["All"]:
+ for dtype in list(np.typecodes["All"]) + ['i4,i4,i4']:
if dtype == 'O':
# object dtype can't be misaligned
continue
diff --git a/numpy/distutils/fcompiler/environment.py b/numpy/distutils/fcompiler/environment.py
index 489784580..4238f35cb 100644
--- a/numpy/distutils/fcompiler/environment.py
+++ b/numpy/distutils/fcompiler/environment.py
@@ -1,6 +1,7 @@
from __future__ import division, absolute_import, print_function
import os
+import warnings
from distutils.dist import Distribution
__metaclass__ = type
@@ -54,8 +55,18 @@ class EnvironmentConfig(object):
if envvar is not None:
envvar_contents = os.environ.get(envvar)
if envvar_contents is not None:
- if var and append and os.environ.get('NPY_DISTUTILS_APPEND_FLAGS', '0') == '1':
- var = var + [envvar_contents]
+ if var and append:
+ if os.environ.get('NPY_DISTUTILS_APPEND_FLAGS', '0') == '1':
+ var = var + [envvar_contents]
+ else:
+ var = envvar_contents
+ if 'NPY_DISTUTILS_APPEND_FLAGS' not in os.environ.keys():
+ msg = "{} is used as is, not appended ".format(envvar) + \
+ "to flags already defined " + \
+ "by numpy.distutils! Use NPY_DISTUTILS_APPEND_FLAGS=1 " + \
+ "to obtain appending behavior instead (this " + \
+ "behavior will become default in a future release)."
+ warnings.warn(msg, UserWarning, stacklevel=3)
else:
var = envvar_contents
if confvar is not None and self._conf:
diff --git a/numpy/distutils/tests/test_fcompiler.py b/numpy/distutils/tests/test_fcompiler.py
index 95e44b051..ba19a97ea 100644
--- a/numpy/distutils/tests/test_fcompiler.py
+++ b/numpy/distutils/tests/test_fcompiler.py
@@ -1,6 +1,8 @@
from __future__ import division, absolute_import, print_function
-from numpy.testing import assert_
+import pytest
+
+from numpy.testing import assert_, suppress_warnings
import numpy.distutils.fcompiler
customizable_flags = [
@@ -25,6 +27,7 @@ def test_fcompiler_flags(monkeypatch):
monkeypatch.setenv(envvar, new_flag)
new_flags = getattr(flag_vars, opt)
+
monkeypatch.delenv(envvar)
assert_(new_flags == [new_flag])
@@ -33,12 +36,46 @@ def test_fcompiler_flags(monkeypatch):
for opt, envvar in customizable_flags:
new_flag = '-dummy-{}-flag'.format(opt)
prev_flags = getattr(flag_vars, opt)
-
monkeypatch.setenv(envvar, new_flag)
new_flags = getattr(flag_vars, opt)
+
monkeypatch.delenv(envvar)
if prev_flags is None:
assert_(new_flags == [new_flag])
else:
assert_(new_flags == prev_flags + [new_flag])
+
+def test_fcompiler_flags_append_warning(monkeypatch):
+ # Test to check that the warning for append behavior changing in future
+ # is triggered. Need to use a real compiler instance so that we have
+ # non-empty flags to start with (otherwise the "if var and append" check
+ # will always be false).
+ try:
+ with suppress_warnings() as sup:
+ sup.record()
+ fc = numpy.distutils.fcompiler.new_fcompiler(compiler='gnu95')
+ fc.customize()
+ except numpy.distutils.fcompiler.CompilerNotFound:
+ pytest.skip("gfortran not found, so can't execute this test")
+
+ # Ensure NPY_DISTUTILS_APPEND_FLAGS not defined
+ monkeypatch.delenv('NPY_DISTUTILS_APPEND_FLAGS', raising=False)
+
+ for opt, envvar in customizable_flags:
+ new_flag = '-dummy-{}-flag'.format(opt)
+ with suppress_warnings() as sup:
+ sup.record()
+ prev_flags = getattr(fc.flag_vars, opt)
+
+ monkeypatch.setenv(envvar, new_flag)
+ with suppress_warnings() as sup:
+ sup.record()
+ new_flags = getattr(fc.flag_vars, opt)
+ if prev_flags:
+ # Check that warning was issued
+ assert len(sup.log) == 1
+
+ monkeypatch.delenv(envvar)
+ assert_(new_flags == [new_flag])
+