summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMark Wiebe <mwiebe@enthought.com>2011-06-23 09:05:53 -0500
committerMark Wiebe <mwiebe@enthought.com>2011-06-23 09:05:53 -0500
commit2e9e8aada9b5ada7841442dba6b111e446a35849 (patch)
treee46baaa325108426f1df8c4581790c93074813ba
parent8b29cac3f3fd68daf95bd89887da1635909c9a35 (diff)
parent09f6a8c97a2fa07864fe0c3b6584d828b9d94b3e (diff)
downloadnumpy-2e9e8aada9b5ada7841442dba6b111e446a35849.tar.gz
Merge branch 'tighten_casting'
-rw-r--r--numpy/core/code_generators/generate_umath.py2
-rw-r--r--numpy/core/src/multiarray/calculation.c25
-rw-r--r--numpy/core/src/umath/ufunc_object.c33
-rw-r--r--numpy/core/src/umath/ufunc_object.h9
-rw-r--r--numpy/core/tests/test_datetime.py39
-rw-r--r--numpy/ma/core.py5
-rw-r--r--numpy/ma/tests/test_core.py4
7 files changed, 88 insertions, 29 deletions
diff --git a/numpy/core/code_generators/generate_umath.py b/numpy/core/code_generators/generate_umath.py
index 957607f40..296f4683d 100644
--- a/numpy/core/code_generators/generate_umath.py
+++ b/numpy/core/code_generators/generate_umath.py
@@ -333,7 +333,7 @@ defdict = {
'ones_like' :
Ufunc(1, 1, None,
docstrings.get('numpy.core.umath.ones_like'),
- 'PyUFunc_SimpleUnaryOperationTypeResolution',
+ 'PyUFunc_OnesLikeTypeResolution',
TD(noobj),
TD(O, f='Py_get_one'),
),
diff --git a/numpy/core/src/multiarray/calculation.c b/numpy/core/src/multiarray/calculation.c
index 8f32ce21c..dc6a7b15d 100644
--- a/numpy/core/src/multiarray/calculation.c
+++ b/numpy/core/src/multiarray/calculation.c
@@ -733,7 +733,30 @@ _GenericBinaryOutFunction(PyArrayObject *m1, PyObject *m2, PyArrayObject *out,
return PyObject_CallFunction(op, "OO", m1, m2);
}
else {
- return PyObject_CallFunction(op, "OOO", m1, m2, out);
+ PyObject *args, *kw, *ret;
+
+ args = Py_BuildValue("OOO", m1, m2, out);
+ if (args == NULL) {
+ return NULL;
+ }
+ kw = PyDict_New();
+ if (kw == NULL) {
+ Py_DECREF(args);
+ return NULL;
+ }
+ if (PyDict_SetItemString(kw, "casting",
+ PyUString_FromString("unsafe")) < 0) {
+ Py_DECREF(args);
+ Py_DECREF(kw);
+ return NULL;
+ }
+
+ ret = PyObject_Call(op, args, kw);
+
+ Py_DECREF(args);
+ Py_DECREF(kw);
+
+ return ret;
}
}
diff --git a/numpy/core/src/umath/ufunc_object.c b/numpy/core/src/umath/ufunc_object.c
index dcc29f2ba..69f9afecf 100644
--- a/numpy/core/src/umath/ufunc_object.c
+++ b/numpy/core/src/umath/ufunc_object.c
@@ -2012,6 +2012,27 @@ PyUFunc_SimpleUnaryOperationTypeResolution(PyUFuncObject *ufunc,
}
/*
+ * The ones_like function shouldn't really be a ufunc, but while it
+ * still is, this provides type resolution that always forces UNSAFE
+ * casting.
+ */
+NPY_NO_EXPORT int
+PyUFunc_OnesLikeTypeResolution(PyUFuncObject *ufunc,
+ NPY_CASTING NPY_UNUSED(casting),
+ PyArrayObject **operands,
+ PyObject *type_tup,
+ PyArray_Descr **out_dtypes,
+ PyUFuncGenericFunction *out_innerloop,
+ void **out_innerloopdata)
+{
+ return PyUFunc_SimpleUnaryOperationTypeResolution(ufunc,
+ NPY_UNSAFE_CASTING,
+ operands, type_tup, out_dtypes,
+ out_innerloop, out_innerloopdata);
+}
+
+
+/*
* This function applies special type resolution rules for the case
* where all the functions have the pattern XX->X, using
* PyArray_ResultType instead of a linear search to get the best
@@ -3486,11 +3507,9 @@ PyUFunc_GeneralizedFunction(PyUFuncObject *self,
NPY_ORDER order = NPY_KEEPORDER;
/*
- * Many things in NumPy do unsafe casting (doing int += float, etc).
- * The strictness should probably become a state parameter, similar
- * to the seterr/geterr.
+ * Currently trying out SAME_KIND casting rule by default.
*/
- NPY_CASTING casting = NPY_UNSAFE_CASTING;
+ NPY_CASTING casting = NPY_SAME_KIND_CASTING;
/* When provided, extobj and typetup contain borrowed references */
PyObject *extobj = NULL, *type_tup = NULL;
@@ -3870,11 +3889,9 @@ PyUFunc_GenericFunction(PyUFuncObject *self,
NPY_ORDER order = NPY_KEEPORDER;
/*
- * Many things in NumPy do unsafe casting (doing int += float, etc).
- * The strictness should probably become a state parameter, similar
- * to the seterr/geterr.
+ * Currently trying out SAME_KIND casting rule by default.
*/
- NPY_CASTING casting = NPY_UNSAFE_CASTING;
+ NPY_CASTING casting = NPY_SAME_KIND_CASTING;
/* When provided, extobj and typetup contain borrowed references */
PyObject *extobj = NULL, *type_tup = NULL;
diff --git a/numpy/core/src/umath/ufunc_object.h b/numpy/core/src/umath/ufunc_object.h
index 2a5fd63a1..59754380c 100644
--- a/numpy/core/src/umath/ufunc_object.h
+++ b/numpy/core/src/umath/ufunc_object.h
@@ -26,6 +26,15 @@ PyUFunc_SimpleUnaryOperationTypeResolution(PyUFuncObject *ufunc,
void **out_innerloopdata);
NPY_NO_EXPORT int
+PyUFunc_OnesLikeTypeResolution(PyUFuncObject *ufunc,
+ NPY_CASTING casting,
+ PyArrayObject **operands,
+ PyObject *type_tup,
+ PyArray_Descr **out_dtypes,
+ PyUFuncGenericFunction *out_innerloop,
+ void **out_innerloopdata);
+
+NPY_NO_EXPORT int
PyUFunc_SimpleBinaryOperationTypeResolution(PyUFuncObject *ufunc,
NPY_CASTING casting,
PyArrayObject **operands,
diff --git a/numpy/core/tests/test_datetime.py b/numpy/core/tests/test_datetime.py
index 9af00a81b..271a5dea9 100644
--- a/numpy/core/tests/test_datetime.py
+++ b/numpy/core/tests/test_datetime.py
@@ -625,10 +625,12 @@ class TestDateTime(TestCase):
dt1 = np.dtype('M8[%s]' % unit1)
for unit2 in ['D', 'h', 'm', 's', 'ms', 'us']:
dt2 = np.dtype('M8[%s]' % unit2)
- assert_equal(np.array('1932-02-17', dtype='M').astype(dt1),
- np.array('1932-02-17T00:00:00Z', dtype='M').astype(dt2))
- assert_equal(np.array('10000-04-27', dtype='M').astype(dt1),
- np.array('10000-04-27T00:00:00Z', dtype='M').astype(dt2))
+ assert_(np.equal(np.array('1932-02-17', dtype='M').astype(dt1),
+ np.array('1932-02-17T00:00:00Z', dtype='M').astype(dt2),
+ casting='unsafe'))
+ assert_(np.equal(np.array('10000-04-27', dtype='M').astype(dt1),
+ np.array('10000-04-27T00:00:00Z', dtype='M').astype(dt2),
+ casting='unsafe'))
# Shouldn't be able to compare datetime and timedelta
# TODO: Changing to 'same_kind' or 'safe' casting in the ufuncs by
@@ -743,10 +745,12 @@ class TestDateTime(TestCase):
assert_equal((tda + dta).dtype, np.dtype('M8[D]'))
# In M8 + m8, the result goes to higher precision
- assert_equal(dta + tdb, dtc)
- assert_equal((dta + tdb).dtype, np.dtype('M8[h]'))
- assert_equal(tdb + dta, dtc)
- assert_equal((tdb + dta).dtype, np.dtype('M8[h]'))
+ assert_equal(np.add(dta, tdb, casting='unsafe'), dtc)
+ assert_equal(np.add(dta, tdb, casting='unsafe').dtype,
+ np.dtype('M8[h]'))
+ assert_equal(np.add(tdb, dta, casting='unsafe'), dtc)
+ assert_equal(np.add(tdb, dta, casting='unsafe').dtype,
+ np.dtype('M8[h]'))
# M8 + M8
assert_raises(TypeError, np.add, dta, dtb)
@@ -805,14 +809,19 @@ class TestDateTime(TestCase):
assert_equal((dtb - tda).dtype, np.dtype('M8[D]'))
# In M8 - m8, the result goes to higher precision
- assert_equal(dtc - tdb, dte)
- assert_equal((dtc - tdb).dtype, np.dtype('M8[h]'))
+ assert_equal(np.subtract(dtc, tdb, casting='unsafe'), dte)
+ assert_equal(np.subtract(dtc, tdb, casting='unsafe').dtype,
+ np.dtype('M8[h]'))
# M8 - M8 with different goes to higher precision
- assert_equal(dtc - dtd, np.timedelta64(0,'h'))
- assert_equal((dtc - dtd).dtype, np.dtype('m8[h]'))
- assert_equal(dtd - dtc, np.timedelta64(0,'h'))
- assert_equal((dtd - dtc).dtype, np.dtype('m8[h]'))
+ assert_equal(np.subtract(dtc, dtd, casting='unsafe'),
+ np.timedelta64(0,'h'))
+ assert_equal(np.subtract(dtc, dtd, casting='unsafe').dtype,
+ np.dtype('m8[h]'))
+ assert_equal(np.subtract(dtd, dtc, casting='unsafe'),
+ np.timedelta64(0,'h'))
+ assert_equal(np.subtract(dtd, dtc, casting='unsafe').dtype,
+ np.dtype('m8[h]'))
# m8 - M8
assert_raises(TypeError, np.subtract, tda, dta)
@@ -926,7 +935,7 @@ class TestDateTime(TestCase):
# Interaction with NaT
a = np.array('1999-03-12T13Z', dtype='M8[2m]')
- dtnat = np.array('NaT', dtype='M8[D]')
+ dtnat = np.array('NaT', dtype='M8[h]')
assert_equal(np.minimum(a,dtnat), a)
assert_equal(np.minimum(dtnat,a), a)
assert_equal(np.maximum(a,dtnat), a)
diff --git a/numpy/ma/core.py b/numpy/ma/core.py
index 2cb888d55..50c60cd9d 100644
--- a/numpy/ma/core.py
+++ b/numpy/ma/core.py
@@ -4771,7 +4771,7 @@ class MaskedArray(ndarray):
if dvar is not masked:
dvar = sqrt(dvar)
if out is not None:
- out **= 0.5
+ np.power(out, 0.5, out=out, casting='unsafe')
return out
return dvar
std.__doc__ = np.std.__doc__
@@ -5207,7 +5207,8 @@ class MaskedArray(ndarray):
result -= self.min(axis=axis, fill_value=fill_value)
return result
out.flat = self.max(axis=axis, out=out, fill_value=fill_value)
- out -= self.min(axis=axis, fill_value=fill_value)
+ min_value = self.min(axis=axis, fill_value=fill_value)
+ np.subtract(out, min_value, out=out, casting='unsafe')
return out
def take(self, indices, axis=None, out=None, mode='raise'):
diff --git a/numpy/ma/tests/test_core.py b/numpy/ma/tests/test_core.py
index 2a2a76c24..b4ec3e540 100644
--- a/numpy/ma/tests/test_core.py
+++ b/numpy/ma/tests/test_core.py
@@ -1031,7 +1031,7 @@ class TestMaskedArrayArithmetic(TestCase):
def test_noshrinking(self):
"Check that we don't shrink a mask when not wanted"
# Binary operations
- a = masked_array([1, 2, 3], mask=[False, False, False], shrink=False)
+ a = masked_array([1., 2., 3.], mask=[False, False, False], shrink=False)
b = a + 1
assert_equal(b.mask, [0, 0, 0])
# In place binary operation
@@ -1646,7 +1646,7 @@ class TestMaskedArrayInPlaceArithmetics(TestCase):
"""Test of inplace additions"""
(x, y, xm) = self.intdata
m = xm.mask
- a = arange(10, dtype=float)
+ a = arange(10, dtype=np.int16)
a[-1] = masked
x += a
xm += a