summaryrefslogtreecommitdiff
path: root/numpy/core
diff options
context:
space:
mode:
Diffstat (limited to 'numpy/core')
-rw-r--r--numpy/core/_methods.py2
-rw-r--r--numpy/core/src/multiarray/common.c32
-rw-r--r--numpy/core/src/multiarray/common.h45
-rw-r--r--numpy/core/src/multiarray/item_selection.c24
-rw-r--r--numpy/core/src/multiarray/nditer_api.c3
-rw-r--r--numpy/core/src/multiarray/number.c6
-rw-r--r--numpy/core/src/multiarray/numpyos.c42
-rw-r--r--numpy/core/src/umath/simd.inc.src48
-rw-r--r--numpy/core/src/umath/ufunc_object.c260
-rw-r--r--numpy/core/tests/test_numeric.py51
-rw-r--r--numpy/core/tests/test_umath.py7
11 files changed, 311 insertions, 209 deletions
diff --git a/numpy/core/_methods.py b/numpy/core/_methods.py
index c8a968c97..a064f70c7 100644
--- a/numpy/core/_methods.py
+++ b/numpy/core/_methods.py
@@ -1,5 +1,5 @@
"""
-Array methods which are called by the both the C-code for the method
+Array methods which are called by both the C-code for the method
and the Python code for the NumPy-namespace function
"""
diff --git a/numpy/core/src/multiarray/common.c b/numpy/core/src/multiarray/common.c
index 9a05133a1..ccd83c8b3 100644
--- a/numpy/core/src/multiarray/common.c
+++ b/numpy/core/src/multiarray/common.c
@@ -53,6 +53,13 @@ PyArray_GetAttrString_SuppressException(PyObject *obj, char *name)
/* We do not need to check for special attributes on trivial types */
if (obj == Py_None ||
+ /* Basic number types */
+#if !defined(NPY_PY3K)
+ PyInt_CheckExact(obj) ||
+#endif
+ PyLong_CheckExact(obj) ||
+ PyFloat_CheckExact(obj) ||
+ /* Basic sequence types */
PyList_CheckExact(obj) ||
PyTuple_CheckExact(obj)) {
return NULL;
@@ -609,31 +616,6 @@ _array_typedescr_fromstr(char *c_str)
return descr;
}
-NPY_NO_EXPORT int
-check_and_adjust_index(npy_intp *index, npy_intp max_item, int axis)
-{
- /* Check that index is valid, taking into account negative indices */
- if ((*index < -max_item) || (*index >= max_item)) {
- /* Try to be as clear as possible about what went wrong. */
- if (axis >= 0) {
- PyErr_Format(PyExc_IndexError,
- "index %"NPY_INTP_FMT" is out of bounds "
- "for axis %d with size %"NPY_INTP_FMT,
- *index, axis, max_item);
- } else {
- PyErr_Format(PyExc_IndexError,
- "index %"NPY_INTP_FMT" is out of bounds "
- "for size %"NPY_INTP_FMT,
- *index, max_item);
- }
- return -1;
- }
- /* adjust negative indices */
- if (*index < 0) {
- *index += max_item;
- }
- return 0;
-}
NPY_NO_EXPORT char *
index2ptr(PyArrayObject *mp, npy_intp i)
diff --git a/numpy/core/src/multiarray/common.h b/numpy/core/src/multiarray/common.h
index 3e060de3d..44b8308f8 100644
--- a/numpy/core/src/multiarray/common.h
+++ b/numpy/core/src/multiarray/common.h
@@ -40,16 +40,6 @@ _array_find_python_scalar_type(PyObject *op);
NPY_NO_EXPORT PyArray_Descr *
_array_typedescr_fromstr(char *str);
-/*
- * Returns -1 and sets an exception if *index is an invalid index for
- * an array of size max_item, otherwise adjusts it in place to be
- * 0 <= *index < max_item, and returns 0.
- * 'axis' should be the array axis that is being indexed over, if known. If
- * unknown, use -1.
- */
-NPY_NO_EXPORT int
-check_and_adjust_index(npy_intp *index, npy_intp max_item, int axis);
-
NPY_NO_EXPORT char *
index2ptr(PyArrayObject *mp, npy_intp i);
@@ -67,6 +57,41 @@ offset_bounds_from_strides(const int itemsize, const int nd,
const npy_intp *dims, const npy_intp *strides,
npy_intp *lower_offset, npy_intp *upper_offset);
+
+/*
+ * Returns -1 and sets an exception if *index is an invalid index for
+ * an array of size max_item, otherwise adjusts it in place to be
+ * 0 <= *index < max_item, and returns 0.
+ * 'axis' should be the array axis that is being indexed over, if known. If
+ * unknown, use -1.
+ */
+static NPY_INLINE int
+check_and_adjust_index(npy_intp *index, npy_intp max_item, int axis)
+{
+ /* Check that index is valid, taking into account negative indices */
+ if ((*index < -max_item) || (*index >= max_item)) {
+ /* Try to be as clear as possible about what went wrong. */
+ if (axis >= 0) {
+ PyErr_Format(PyExc_IndexError,
+ "index %"NPY_INTP_FMT" is out of bounds "
+ "for axis %d with size %"NPY_INTP_FMT,
+ *index, axis, max_item);
+ } else {
+ PyErr_Format(PyExc_IndexError,
+ "index %"NPY_INTP_FMT" is out of bounds "
+ "for size %"NPY_INTP_FMT,
+ *index, max_item);
+ }
+ return -1;
+ }
+ /* adjust negative indices */
+ if (*index < 0) {
+ *index += max_item;
+ }
+ return 0;
+}
+
+
/*
* return true if pointer is aligned to 'alignment'
*/
diff --git a/numpy/core/src/multiarray/item_selection.c b/numpy/core/src/multiarray/item_selection.c
index 72cbf9a22..bc076ba83 100644
--- a/numpy/core/src/multiarray/item_selection.c
+++ b/numpy/core/src/multiarray/item_selection.c
@@ -1209,7 +1209,7 @@ partition_prep_kth_array(PyArrayObject * ktharray,
PyErr_Format(PyExc_ValueError, "kth array must have dimension <= 1");
return NULL;
}
- kthrvl = PyArray_Cast(ktharray, NPY_INTP);
+ kthrvl = (PyArrayObject *)PyArray_Cast(ktharray, NPY_INTP);
if (kthrvl == NULL)
return NULL;
@@ -2236,10 +2236,9 @@ PyArray_Diagonal(PyArrayObject *self, int offset, int axis1, int axis2)
char *data;
npy_intp diag_size;
- PyArrayObject *ret;
PyArray_Descr *dtype;
+ PyObject *ret;
npy_intp ret_shape[NPY_MAXDIMS], ret_strides[NPY_MAXDIMS];
- PyObject *copy;
if (ndim < 2) {
PyErr_SetString(PyExc_ValueError,
@@ -2325,7 +2324,7 @@ PyArray_Diagonal(PyArrayObject *self, int offset, int axis1, int axis2)
/* Create the diagonal view */
dtype = PyArray_DTYPE(self);
Py_INCREF(dtype);
- ret = (PyArrayObject *)PyArray_NewFromDescr(Py_TYPE(self),
+ ret = PyArray_NewFromDescr(Py_TYPE(self),
dtype,
ndim-1, ret_shape,
ret_strides,
@@ -2336,7 +2335,7 @@ PyArray_Diagonal(PyArrayObject *self, int offset, int axis1, int axis2)
return NULL;
}
Py_INCREF(self);
- if (PyArray_SetBaseObject(ret, (PyObject *)self) < 0) {
+ if (PyArray_SetBaseObject((PyArrayObject *)ret, (PyObject *)self) < 0) {
Py_DECREF(ret);
return NULL;
}
@@ -2345,7 +2344,7 @@ PyArray_Diagonal(PyArrayObject *self, int offset, int axis1, int axis2)
* For numpy 1.9 the diagonal view is not writeable.
* This line needs to be removed in 1.10.
*/
- PyArray_CLEARFLAGS(ret, NPY_ARRAY_WRITEABLE);
+ PyArray_CLEARFLAGS((PyArrayObject *)ret, NPY_ARRAY_WRITEABLE);
return ret;
}
@@ -2402,10 +2401,11 @@ PyArray_Compress(PyArrayObject *self, PyObject *condition, int axis,
* but a 32 bit type version would make it even faster on these platforms
*/
static NPY_INLINE int
-count_nonzero_bytes_128(npy_uint64 * w)
+count_nonzero_bytes_128(const char *w)
{
- npy_uint64 w1 = w[0];
- npy_uint64 w2 = w[1];
+ const npy_uint64 *w64 = (const npy_uint64 *)w;
+ npy_uint64 w1 = w64[0];
+ npy_uint64 w2 = w64[1];
/*
* bytes not exclusively 0 or 1, sum them individually.
@@ -2414,7 +2414,7 @@ count_nonzero_bytes_128(npy_uint64 * w)
*/
if (NPY_UNLIKELY(((w1 | w2) & 0xFEFEFEFEFEFEFEFEULL) != 0)) {
/* reload from pointer to avoid a unnecessary stack spill with gcc */
- char * c = (char *)w;
+ const char *c = w;
npy_uintp i, count = 0;
for (i = 0; i < 16; i++) {
count += (c[i] != 0);
@@ -2464,8 +2464,8 @@ count_boolean_trues(int ndim, char *data, npy_intp *ashape, npy_intp *astrides)
if (strides[0] == 1) {
NPY_RAW_ITER_START(idim, ndim, coord, shape) {
/* Process the innermost dimension */
- char * d = data;
- char * e = data + shape[0];
+ const char *d = data;
+ const char *e = data + shape[0];
if (npy_is_aligned(data, sizeof(npy_uint64))) {
npy_uintp stride = 2 * sizeof(npy_uint64);
for (; d < e - (shape[0] % stride); d += stride) {
diff --git a/numpy/core/src/multiarray/nditer_api.c b/numpy/core/src/multiarray/nditer_api.c
index 164a3a7a3..905a19d55 100644
--- a/numpy/core/src/multiarray/nditer_api.c
+++ b/numpy/core/src/multiarray/nditer_api.c
@@ -1832,8 +1832,7 @@ npyiter_copy_from_buffers(NpyIter *iter)
*reduce_outeraxisdata = NULL;
PyArray_Descr **dtypes = NIT_DTYPES(iter);
- npy_intp transfersize = NBF_SIZE(bufferdata),
- buffersize = NBF_BUFFERSIZE(bufferdata);
+ npy_intp transfersize = NBF_SIZE(bufferdata);
npy_intp *strides = NBF_STRIDES(bufferdata),
*ad_strides = NAD_STRIDES(axisdata);
npy_intp sizeof_axisdata = NIT_AXISDATA_SIZEOF(itflags, ndim, nop);
diff --git a/numpy/core/src/multiarray/number.c b/numpy/core/src/multiarray/number.c
index 1b665fecb..2ad65bbe8 100644
--- a/numpy/core/src/multiarray/number.c
+++ b/numpy/core/src/multiarray/number.c
@@ -277,8 +277,10 @@ PyArray_GenericBinaryFunction(PyArrayObject *m1, PyObject *m2, PyObject *op)
* - https://github.com/numpy/numpy/issues/3502
* - https://github.com/numpy/numpy/issues/3503
*/
- double m1_prio = PyArray_GetPriority(m1, NPY_SCALAR_PRIORITY);
- double m2_prio = PyArray_GetPriority(m2, NPY_SCALAR_PRIORITY);
+ double m1_prio = PyArray_GetPriority((PyObject *)m1,
+ NPY_SCALAR_PRIORITY);
+ double m2_prio = PyArray_GetPriority((PyObject *)m2,
+ NPY_SCALAR_PRIORITY);
if (m1_prio < m2_prio) {
Py_INCREF(Py_NotImplemented);
return Py_NotImplemented;
diff --git a/numpy/core/src/multiarray/numpyos.c b/numpy/core/src/multiarray/numpyos.c
index 23ba57e5d..44b32f4da 100644
--- a/numpy/core/src/multiarray/numpyos.c
+++ b/numpy/core/src/multiarray/numpyos.c
@@ -26,7 +26,7 @@
* in length.
*/
static void
-_ensure_minimum_exponent_length(char* buffer, size_t buf_size)
+ensure_minimum_exponent_length(char* buffer, size_t buf_size)
{
char *p = strpbrk(buffer, "eE");
if (p && (*(p + 1) == '-' || *(p + 1) == '+')) {
@@ -101,7 +101,7 @@ _ensure_minimum_exponent_length(char* buffer, size_t buf_size)
* will not be in the current locale, it will always be '.'
*/
static void
-_ensure_decimal_point(char* buffer, size_t buf_size)
+ensure_decimal_point(char* buffer, size_t buf_size)
{
int insert_count = 0;
char* chars_to_insert;
@@ -163,7 +163,7 @@ _ensure_decimal_point(char* buffer, size_t buf_size)
* longer, no need for a maximum buffer size parameter.
*/
static void
-_change_decimal_from_locale_to_dot(char* buffer)
+change_decimal_from_locale_to_dot(char* buffer)
{
struct lconv *locale_data = localeconv();
const char *decimal_point = locale_data->decimal_point;
@@ -194,7 +194,7 @@ _change_decimal_from_locale_to_dot(char* buffer)
* Check that the format string is a valid one for NumPyOS_ascii_format*
*/
static int
-_check_ascii_format(const char *format)
+check_ascii_format(const char *format)
{
char format_char;
size_t format_len = strlen(format);
@@ -238,13 +238,13 @@ _check_ascii_format(const char *format)
* PyOS_ascii_formatd
*/
static char*
-_fix_ascii_format(char* buf, size_t buflen, int decimal)
+fix_ascii_format(char* buf, size_t buflen, int decimal)
{
/*
* Get the current locale, and find the decimal point string.
* Convert that string back to a dot.
*/
- _change_decimal_from_locale_to_dot(buf);
+ change_decimal_from_locale_to_dot(buf);
/*
* If an exponent exists, ensure that the exponent is at least
@@ -253,10 +253,10 @@ _fix_ascii_format(char* buf, size_t buflen, int decimal)
* MIN_EXPONENT_DIGITS, remove as many zeros as possible until we get
* back to MIN_EXPONENT_DIGITS
*/
- _ensure_minimum_exponent_length(buf, buflen);
+ ensure_minimum_exponent_length(buf, buflen);
if (decimal != 0) {
- _ensure_decimal_point(buf, buflen);
+ ensure_decimal_point(buf, buflen);
}
return buf;
@@ -282,18 +282,18 @@ _fix_ascii_format(char* buf, size_t buflen, int decimal)
*
* Return value: The pointer to the buffer with the converted string.
*/
-#define _ASCII_FORMAT(type, suffix, print_type) \
+#define ASCII_FORMAT(type, suffix, print_type) \
NPY_NO_EXPORT char* \
NumPyOS_ascii_format ## suffix(char *buffer, size_t buf_size, \
const char *format, \
type val, int decimal) \
{ \
if (npy_isfinite(val)) { \
- if(_check_ascii_format(format)) { \
+ if (check_ascii_format(format)) { \
return NULL; \
} \
PyOS_snprintf(buffer, buf_size, format, (print_type)val); \
- return _fix_ascii_format(buffer, buf_size, decimal); \
+ return fix_ascii_format(buffer, buf_size, decimal); \
} \
else if (npy_isnan(val)){ \
if (buf_size < 4) { \
@@ -318,12 +318,12 @@ _fix_ascii_format(char* buf, size_t buflen, int decimal)
return buffer; \
}
-_ASCII_FORMAT(float, f, float)
-_ASCII_FORMAT(double, d, double)
+ASCII_FORMAT(float, f, float)
+ASCII_FORMAT(double, d, double)
#ifndef FORCE_NO_LONG_DOUBLE_FORMATTING
-_ASCII_FORMAT(long double, l, long double)
+ASCII_FORMAT(long double, l, long double)
#else
-_ASCII_FORMAT(long double, l, double)
+ASCII_FORMAT(long double, l, double)
#endif
/*
@@ -380,8 +380,8 @@ NumPyOS_ascii_isalnum(char c)
*
* Same as tolower under C locale
*/
-static char
-NumPyOS_ascii_tolower(char c)
+static int
+NumPyOS_ascii_tolower(int c)
{
if (c >= 'A' && c <= 'Z') {
return c + ('a'-'A');
@@ -398,10 +398,8 @@ NumPyOS_ascii_tolower(char c)
static int
NumPyOS_ascii_strncasecmp(const char* s1, const char* s2, size_t len)
{
- int diff;
while (len > 0 && *s1 != '\0' && *s2 != '\0') {
- diff = ((int)NumPyOS_ascii_tolower(*s1)) -
- ((int)NumPyOS_ascii_tolower(*s2));
+ int diff = NumPyOS_ascii_tolower(*s1) - NumPyOS_ascii_tolower(*s2);
if (diff != 0) {
return diff;
}
@@ -410,13 +408,13 @@ NumPyOS_ascii_strncasecmp(const char* s1, const char* s2, size_t len)
--len;
}
if (len > 0) {
- return ((int)*s1) - ((int)*s2);
+ return *s1 - *s2;
}
return 0;
}
/*
- * _NumPyOS_ascii_strtod_plain:
+ * NumPyOS_ascii_strtod_plain:
*
* PyOS_ascii_strtod work-alike, with no enhanced features,
* for forward compatibility with Python >= 2.7
diff --git a/numpy/core/src/umath/simd.inc.src b/numpy/core/src/umath/simd.inc.src
index e274e0596..e5c4e9335 100644
--- a/numpy/core/src/umath/simd.inc.src
+++ b/numpy/core/src/umath/simd.inc.src
@@ -138,6 +138,7 @@ static const npy_int32 fanout_4[] = {
* #func = sqrt, absolute, minimum, maximum#
* #check = IS_BLOCKABLE_UNARY, IS_BLOCKABLE_UNARY, IS_BLOCKABLE_REDUCE, IS_BLOCKABLE_REDUCE#
* #name = unary, unary, unary_reduce, unary_reduce#
+ * #minmax = 0, 0, 1, 1#
*/
#if @vector@ && defined NPY_HAVE_SSE2_INTRINSICS
@@ -151,6 +152,9 @@ sse2_@func@_@TYPE@(@type@ *, @type@ *, const npy_intp n);
static NPY_INLINE int
run_@name@_simd_@func@_@TYPE@(char **args, npy_intp *dimensions, npy_intp *steps)
{
+#if @minmax@ && (defined NO_FLOATING_POINT_SUPPORT)
+ return 0;
+#else
#if @vector@ && defined NPY_HAVE_SSE2_INTRINSICS
if (@check@(sizeof(@type@), 16)) {
sse2_@func@_@TYPE@((@type@*)args[1], (@type@*)args[0], dimensions[0]);
@@ -158,6 +162,7 @@ run_@name@_simd_@func@_@TYPE@(char **args, npy_intp *dimensions, npy_intp *steps
}
#endif
return 0;
+#endif
}
/**end repeat1**/
@@ -660,42 +665,33 @@ sse2_absolute_@TYPE@(@type@ * op, @type@ * ip, const npy_intp n)
static void
sse2_@kind@_@TYPE@(@type@ * ip, @type@ * op, const npy_intp n)
{
+ const size_t stride = 16 / sizeof(@type@);
LOOP_BLOCK_ALIGN_VAR(ip, @type@, 16) {
*op = (*op @OP@ ip[i] || npy_isnan(*op)) ? *op : ip[i];
}
- assert(n < (16 / sizeof(@type@)) || npy_is_aligned(&ip[i], 16));
- if (i + 2 * 16 / sizeof(@type@) <= n) {
+ assert(n < (stride) || npy_is_aligned(&ip[i], 16));
+ if (i + 3 * stride <= n) {
/* load the first elements */
- @vtype@ c = @vpre@_load_@vsuf@((@type@*)&ip[i]);
-#ifdef NO_FLOATING_POINT_SUPPORT
- @vtype@ cnan = @vpre@_cmpneq_@vsuf@(c, c);
-#else
+ @vtype@ c1 = @vpre@_load_@vsuf@((@type@*)&ip[i]);
+ @vtype@ c2 = @vpre@_load_@vsuf@((@type@*)&ip[i + stride]);
+ i += 2 * stride;
+
/* minps/minpd will set invalid flag if nan is encountered */
PyUFunc_clearfperr();
-#endif
- i += 16 / sizeof(@type@);
-
- LOOP_BLOCKED(@type@, 16) {
- @vtype@ v = @vpre@_load_@vsuf@((@type@*)&ip[i]);
- c = @vpre@_@VOP@_@vsuf@(c, v);
-#ifdef NO_FLOATING_POINT_SUPPORT
- /* check for nan, breaking the loop makes non nan case slow */
- cnan = @vpre@_or_@vsuf@(@vpre@_cmpneq_@vsuf@(v, v), cnan);
+ LOOP_BLOCKED(@type@, 32) {
+ @vtype@ v1 = @vpre@_load_@vsuf@((@type@*)&ip[i]);
+ @vtype@ v2 = @vpre@_load_@vsuf@((@type@*)&ip[i + stride]);
+ c1 = @vpre@_@VOP@_@vsuf@(c1, v1);
+ c2 = @vpre@_@VOP@_@vsuf@(c2, v2);
}
+ c1 = @vpre@_@VOP@_@vsuf@(c1, c2);
- if (@vpre@_movemask_@vsuf@(cnan)) {
+ if (PyUFunc_getfperr() & UFUNC_FPE_INVALID) {
*op = @nan@;
- return;
- }
-#else
}
-#endif
- {
- @type@ tmp = sse2_horizontal_@VOP@_@vtype@(c);
- if (PyUFunc_getfperr() & UFUNC_FPE_INVALID)
- *op = @nan@;
- else
- *op = (*op @OP@ tmp || npy_isnan(*op)) ? *op : tmp;
+ else {
+ @type@ tmp = sse2_horizontal_@VOP@_@vtype@(c1);
+ *op = (*op @OP@ tmp || npy_isnan(*op)) ? *op : tmp;
}
}
LOOP_BLOCKED_END {
diff --git a/numpy/core/src/umath/ufunc_object.c b/numpy/core/src/umath/ufunc_object.c
index 7637d68e6..e419a6611 100644
--- a/numpy/core/src/umath/ufunc_object.c
+++ b/numpy/core/src/umath/ufunc_object.c
@@ -73,11 +73,16 @@ static int
_does_loop_use_arrays(void *data);
static int
+_extract_pyvals(PyObject *ref, char *name, int *bufsize,
+ int *errmask, PyObject **errobj);
+
+static int
assign_reduce_identity_zero(PyArrayObject *result, void *data);
static int
assign_reduce_identity_one(PyArrayObject *result, void *data);
+
/*
* fpstatus is the ufunc_formatted hardware status
* errmask is the handling mask specified by the user.
@@ -225,6 +230,53 @@ PyUFunc_clearfperr()
PyUFunc_getfperr();
}
+
+#if USE_USE_DEFAULTS==1
+static int PyUFunc_NUM_NODEFAULTS = 0;
+#endif
+static PyObject *PyUFunc_PYVALS_NAME = NULL;
+
+static PyObject *
+_get_global_ext_obj(char * name)
+{
+ PyObject *thedict;
+ PyObject *ref = NULL;
+
+#if USE_USE_DEFAULTS==1
+ if (PyUFunc_NUM_NODEFAULTS != 0) {
+#endif
+ if (PyUFunc_PYVALS_NAME == NULL) {
+ PyUFunc_PYVALS_NAME = PyUString_InternFromString(UFUNC_PYVALS_NAME);
+ }
+ thedict = PyThreadState_GetDict();
+ if (thedict == NULL) {
+ thedict = PyEval_GetBuiltins();
+ }
+ ref = PyDict_GetItem(thedict, PyUFunc_PYVALS_NAME);
+#if USE_USE_DEFAULTS==1
+ }
+#endif
+
+ return ref;
+}
+
+
+static int
+_get_bufsize_errmask(PyObject * extobj, char * ufunc_name,
+ int *buffersize, int *errormask)
+{
+ /* Get the buffersize and errormask */
+ if (extobj == NULL) {
+ extobj = _get_global_ext_obj(ufunc_name);
+ }
+ if (_extract_pyvals(extobj, ufunc_name,
+ buffersize, errormask, NULL) < 0) {
+ return -1;
+ }
+
+ return 0;
+}
+
/*
* This function analyzes the input arguments
* and determines an appropriate __array_prepare__ function to call
@@ -363,16 +415,12 @@ _find_array_prepare(PyObject *args, PyObject *kwds,
return;
}
-#if USE_USE_DEFAULTS==1
-static int PyUFunc_NUM_NODEFAULTS = 0;
-#endif
-static PyObject *PyUFunc_PYVALS_NAME = NULL;
-
-
/*
* Extracts some values from the global pyvals tuple.
+ * all destinations may be NULL, in which case they are not retrieved
* ref - should hold the global tuple
* name - is the name of the ufunc (ufuncobj->name)
+ *
* bufsize - receives the buffer size to use
* errmask - receives the bitmask for error handling
* errobj - receives the python object to call with the error,
@@ -384,62 +432,74 @@ _extract_pyvals(PyObject *ref, char *name, int *bufsize,
{
PyObject *retval;
- *errobj = NULL;
+ if (ref == NULL) {
+ *errmask = UFUNC_ERR_DEFAULT;
+ *errobj = Py_BuildValue("NO", PyBytes_FromString(name), Py_None);
+ *bufsize = NPY_BUFSIZE;
+ return 0;
+ }
+
if (!PyList_Check(ref) || (PyList_GET_SIZE(ref)!=3)) {
PyErr_Format(PyExc_TypeError,
"%s must be a length 3 list.", UFUNC_PYVALS_NAME);
return -1;
}
- *bufsize = PyInt_AsLong(PyList_GET_ITEM(ref, 0));
- if ((*bufsize == -1) && PyErr_Occurred()) {
- return -1;
- }
- if ((*bufsize < NPY_MIN_BUFSIZE) ||
- (*bufsize > NPY_MAX_BUFSIZE) ||
- (*bufsize % 16 != 0)) {
- PyErr_Format(PyExc_ValueError,
- "buffer size (%d) is not in range "
- "(%"NPY_INTP_FMT" - %"NPY_INTP_FMT") or not a multiple of 16",
- *bufsize, (npy_intp) NPY_MIN_BUFSIZE,
- (npy_intp) NPY_MAX_BUFSIZE);
- return -1;
- }
-
- *errmask = PyInt_AsLong(PyList_GET_ITEM(ref, 1));
- if (*errmask < 0) {
- if (PyErr_Occurred()) {
+ if (bufsize != NULL) {
+ *bufsize = PyInt_AsLong(PyList_GET_ITEM(ref, 0));
+ if ((*bufsize == -1) && PyErr_Occurred()) {
+ return -1;
+ }
+ if ((*bufsize < NPY_MIN_BUFSIZE) ||
+ (*bufsize > NPY_MAX_BUFSIZE) ||
+ (*bufsize % 16 != 0)) {
+ PyErr_Format(PyExc_ValueError,
+ "buffer size (%d) is not in range "
+ "(%"NPY_INTP_FMT" - %"NPY_INTP_FMT") or not a multiple of 16",
+ *bufsize, (npy_intp) NPY_MIN_BUFSIZE,
+ (npy_intp) NPY_MAX_BUFSIZE);
return -1;
}
- PyErr_Format(PyExc_ValueError,
- "invalid error mask (%d)",
- *errmask);
- return -1;
}
- retval = PyList_GET_ITEM(ref, 2);
- if (retval != Py_None && !PyCallable_Check(retval)) {
- PyObject *temp;
- temp = PyObject_GetAttrString(retval, "write");
- if (temp == NULL || !PyCallable_Check(temp)) {
- PyErr_SetString(PyExc_TypeError,
- "python object must be callable or have " \
- "a callable write method");
- Py_XDECREF(temp);
+ if (errmask != NULL) {
+ *errmask = PyInt_AsLong(PyList_GET_ITEM(ref, 1));
+ if (*errmask < 0) {
+ if (PyErr_Occurred()) {
+ return -1;
+ }
+ PyErr_Format(PyExc_ValueError,
+ "invalid error mask (%d)",
+ *errmask);
return -1;
}
- Py_DECREF(temp);
}
- *errobj = Py_BuildValue("NO", PyBytes_FromString(name), retval);
- if (*errobj == NULL) {
- return -1;
+ if (errobj != NULL) {
+ *errobj = NULL;
+ retval = PyList_GET_ITEM(ref, 2);
+ if (retval != Py_None && !PyCallable_Check(retval)) {
+ PyObject *temp;
+ temp = PyObject_GetAttrString(retval, "write");
+ if (temp == NULL || !PyCallable_Check(temp)) {
+ PyErr_SetString(PyExc_TypeError,
+ "python object must be callable or have " \
+ "a callable write method");
+ Py_XDECREF(temp);
+ return -1;
+ }
+ Py_DECREF(temp);
+ }
+
+ *errobj = Py_BuildValue("NO", PyBytes_FromString(name), retval);
+ if (*errobj == NULL) {
+ return -1;
+ }
}
return 0;
}
-
/*UFUNC_API
*
* On return, if errobj is populated with a non-NULL value, the caller
@@ -449,28 +509,8 @@ NPY_NO_EXPORT int
PyUFunc_GetPyValues(char *name, int *bufsize, int *errmask, PyObject **errobj)
{
PyObject *thedict;
- PyObject *ref = NULL;
+ PyObject *ref = _get_global_ext_obj(name);
-#if USE_USE_DEFAULTS==1
- if (PyUFunc_NUM_NODEFAULTS != 0) {
-#endif
- if (PyUFunc_PYVALS_NAME == NULL) {
- PyUFunc_PYVALS_NAME = PyUString_InternFromString(UFUNC_PYVALS_NAME);
- }
- thedict = PyThreadState_GetDict();
- if (thedict == NULL) {
- thedict = PyEval_GetBuiltins();
- }
- ref = PyDict_GetItem(thedict, PyUFunc_PYVALS_NAME);
-#if USE_USE_DEFAULTS==1
- }
-#endif
- if (ref == NULL) {
- *errmask = UFUNC_ERR_DEFAULT;
- *errobj = Py_BuildValue("NO", PyBytes_FromString(name), Py_None);
- *bufsize = NPY_BUFSIZE;
- return 0;
- }
return _extract_pyvals(ref, name, bufsize, errmask, errobj);
}
@@ -1715,6 +1755,45 @@ make_arr_prep_args(npy_intp nin, PyObject *args, PyObject *kwds)
}
}
+/*
+ * check the floating point status
+ * - errmask: mask of status to check
+ * - extobj: ufunc pyvals object
+ * may be null, in which case the thread global one is fetched
+ * - ufunc_name: name of ufunc
+ */
+static int
+_check_ufunc_fperr(int errmask, PyObject *extobj, char* ufunc_name) {
+ int fperr;
+ PyObject *errobj = NULL;
+ int ret;
+ int first = 1;
+
+ if (!errmask) {
+ return 0;
+ }
+ fperr = PyUFunc_getfperr();
+ if (!fperr) {
+ return 0;
+ }
+
+ /* Get error object globals */
+ if (extobj == NULL) {
+ extobj = _get_global_ext_obj(ufunc_name);
+ }
+ if (_extract_pyvals(extobj, ufunc_name,
+ NULL, NULL, &errobj) < 0) {
+ Py_XDECREF(errobj);
+ return -1;
+ }
+
+ ret = PyUFunc_handlefperr(errmask, errobj, fperr, &first);
+ Py_XDECREF(errobj);
+
+ return ret;
+}
+
+
static int
PyUFunc_GeneralizedFunction(PyUFuncObject *ufunc,
PyObject *args, PyObject *kwds,
@@ -1740,8 +1819,6 @@ PyUFunc_GeneralizedFunction(PyUFuncObject *ufunc,
/* These parameters come from extobj= or from a TLS global */
int buffersize = 0, errormask = 0;
- PyObject *errobj = NULL;
- int first_error = 1;
/* The selected inner loop */
PyUFuncGenericFunction innerloop = NULL;
@@ -1944,20 +2021,10 @@ PyUFunc_GeneralizedFunction(PyUFuncObject *ufunc,
core_dim_ixs_size += ufunc->core_num_dims[i];
}
- /* Get the buffersize, errormask, and error object globals */
- if (extobj == NULL) {
- if (PyUFunc_GetPyValues(ufunc_name,
- &buffersize, &errormask, &errobj) < 0) {
- retval = -1;
- goto fail;
- }
- }
- else {
- if (_extract_pyvals(extobj, ufunc_name,
- &buffersize, &errormask, &errobj) < 0) {
- retval = -1;
- goto fail;
- }
+ /* Get the buffersize and errormask */
+ if (_get_bufsize_errmask(extobj, ufunc_name, &buffersize, &errormask) < 0) {
+ retval = -1;
+ goto fail;
}
NPY_UF_DBG_PRINT("Finding inner loop\n");
@@ -2203,8 +2270,8 @@ PyUFunc_GeneralizedFunction(PyUFuncObject *ufunc,
}
/* Check whether any errors occurred during the loop */
- if (PyErr_Occurred() || (errormask &&
- PyUFunc_checkfperr(errormask, errobj, &first_error))) {
+ if (PyErr_Occurred() ||
+ _check_ufunc_fperr(errormask, extobj, ufunc_name) < 0) {
retval = -1;
goto fail;
}
@@ -2216,7 +2283,6 @@ PyUFunc_GeneralizedFunction(PyUFuncObject *ufunc,
Py_XDECREF(dtypes[i]);
Py_XDECREF(arr_prep[i]);
}
- Py_XDECREF(errobj);
Py_XDECREF(type_tup);
Py_XDECREF(arr_prep_args);
@@ -2234,7 +2300,6 @@ fail:
Py_XDECREF(dtypes[i]);
Py_XDECREF(arr_prep[i]);
}
- Py_XDECREF(errobj);
Py_XDECREF(type_tup);
Py_XDECREF(arr_prep_args);
@@ -2263,8 +2328,6 @@ PyUFunc_GenericFunction(PyUFuncObject *ufunc,
/* These parameters come from extobj= or from a TLS global */
int buffersize = 0, errormask = 0;
- PyObject *errobj = NULL;
- int first_error = 1;
/* The mask provided in the 'where=' parameter */
PyArrayObject *wheremask = NULL;
@@ -2326,20 +2389,10 @@ PyUFunc_GenericFunction(PyUFuncObject *ufunc,
need_fancy = 1;
}
- /* Get the buffersize, errormask, and error object globals */
- if (extobj == NULL) {
- if (PyUFunc_GetPyValues(ufunc_name,
- &buffersize, &errormask, &errobj) < 0) {
- retval = -1;
- goto fail;
- }
- }
- else {
- if (_extract_pyvals(extobj, ufunc_name,
- &buffersize, &errormask, &errobj) < 0) {
- retval = -1;
- goto fail;
- }
+ /* Get the buffersize and errormask */
+ if (_get_bufsize_errmask(extobj, ufunc_name, &buffersize, &errormask) < 0) {
+ retval = -1;
+ goto fail;
}
NPY_UF_DBG_PRINT("Finding inner loop\n");
@@ -2449,18 +2502,18 @@ PyUFunc_GenericFunction(PyUFuncObject *ufunc,
}
/* Check whether any errors occurred during the loop */
- if (PyErr_Occurred() || (errormask &&
- PyUFunc_checkfperr(errormask, errobj, &first_error))) {
+ if (PyErr_Occurred() ||
+ _check_ufunc_fperr(errormask, extobj, ufunc_name) < 0) {
retval = -1;
goto fail;
}
+
/* The caller takes ownership of all the references in op */
for (i = 0; i < nop; ++i) {
Py_XDECREF(dtypes[i]);
Py_XDECREF(arr_prep[i]);
}
- Py_XDECREF(errobj);
Py_XDECREF(type_tup);
Py_XDECREF(arr_prep_args);
Py_XDECREF(wheremask);
@@ -2477,7 +2530,6 @@ fail:
Py_XDECREF(dtypes[i]);
Py_XDECREF(arr_prep[i]);
}
- Py_XDECREF(errobj);
Py_XDECREF(type_tup);
Py_XDECREF(arr_prep_args);
Py_XDECREF(wheremask);
diff --git a/numpy/core/tests/test_numeric.py b/numpy/core/tests/test_numeric.py
index 913599e09..5a3de8edd 100644
--- a/numpy/core/tests/test_numeric.py
+++ b/numpy/core/tests/test_numeric.py
@@ -409,6 +409,36 @@ class TestSeterr(TestCase):
seterr(divide='ignore')
array([1.]) / array([0.])
+ def test_errobj(self):
+ olderrobj = np.geterrobj()
+ self.called = 0
+ try:
+ with warnings.catch_warnings(record=True) as w:
+ warnings.simplefilter("always")
+ with errstate(divide='warn'):
+ np.seterrobj([20000, 1, None])
+ array([1.]) / array([0.])
+ self.assertEqual(len(w), 1)
+
+ def log_err(*args):
+ self.called += 1
+ extobj_err = args
+ assert (len(extobj_err) == 2)
+ assert ("divide" in extobj_err[0])
+
+ with errstate(divide='ignore'):
+ np.seterrobj([20000, 3, log_err])
+ array([1.]) / array([0.])
+ self.assertEqual(self.called, 1)
+
+ np.seterrobj(olderrobj)
+ with errstate(divide='ignore'):
+ np.divide(1., 0., extobj=[20000, 3, log_err])
+ self.assertEqual(self.called, 2)
+ finally:
+ np.seterrobj(olderrobj)
+ del self.called
+
class TestFloatExceptions(TestCase):
def assert_raises_fpe(self, fpeerr, flop, x, y):
@@ -433,7 +463,7 @@ class TestFloatExceptions(TestCase):
self.assert_raises_fpe(fpeerr, flop, sc1, sc2[()]);
self.assert_raises_fpe(fpeerr, flop, sc1[()], sc2[()]);
- @dec.knownfailureif(True, "See ticket 1755")
+ @dec.knownfailureif(True, "See ticket #2350")
def test_floating_exceptions(self):
# Test basic arithmetic function errors
with np.errstate(all='raise'):
@@ -488,6 +518,25 @@ class TestFloatExceptions(TestCase):
self.assert_raises_fpe(invalid,
lambda a, b:a*b, ftype(0), ftype(np.inf))
+ def test_warnings(self):
+ # test warning code path
+ with warnings.catch_warnings(record=True) as w:
+ warnings.simplefilter("always")
+ with np.errstate(all="warn"):
+ np.divide(1, 0.)
+ self.assertEqual(len(w), 1)
+ self.assertTrue("divide by zero" in str(w[0].message))
+ np.array(1e300) * np.array(1e300)
+ self.assertEqual(len(w), 2)
+ self.assertTrue("overflow" in str(w[-1].message))
+ np.array(np.inf) - np.array(np.inf)
+ self.assertEqual(len(w), 3)
+ self.assertTrue("invalid value" in str(w[-1].message))
+ np.array(1e-300) * np.array(1e-300)
+ self.assertEqual(len(w), 4)
+ self.assertTrue("underflow" in str(w[-1].message))
+
+
class TestTypes(TestCase):
def check_promotion_cases(self, promote_func):
#Tests that the scalars get coerced correctly.
diff --git a/numpy/core/tests/test_umath.py b/numpy/core/tests/test_umath.py
index 7bcec3114..56e7311e2 100644
--- a/numpy/core/tests/test_umath.py
+++ b/numpy/core/tests/test_umath.py
@@ -678,10 +678,9 @@ class TestMinMax(TestCase):
for i in range(inp.size):
inp[:] = np.arange(inp.size, dtype=dt)
inp[i] = np.nan
- self.assertTrue(np.isnan(inp.max()),
- msg=repr(inp) + '\n' + msg)
- self.assertTrue(np.isnan(inp.min()),
- msg=repr(inp) + '\n' + msg)
+ emsg = lambda: '%r\n%s' % (inp, msg)
+ assert_(np.isnan(inp.max()), msg=emsg)
+ assert_(np.isnan(inp.min()), msg=emsg)
inp[i] = 1e10
assert_equal(inp.max(), 1e10, err_msg=msg)