diff options
Diffstat (limited to 'numpy/core')
-rw-r--r-- | numpy/core/_methods.py | 2 | ||||
-rw-r--r-- | numpy/core/src/multiarray/common.c | 32 | ||||
-rw-r--r-- | numpy/core/src/multiarray/common.h | 45 | ||||
-rw-r--r-- | numpy/core/src/multiarray/item_selection.c | 24 | ||||
-rw-r--r-- | numpy/core/src/multiarray/nditer_api.c | 3 | ||||
-rw-r--r-- | numpy/core/src/multiarray/number.c | 6 | ||||
-rw-r--r-- | numpy/core/src/multiarray/numpyos.c | 42 | ||||
-rw-r--r-- | numpy/core/src/umath/simd.inc.src | 48 | ||||
-rw-r--r-- | numpy/core/src/umath/ufunc_object.c | 260 | ||||
-rw-r--r-- | numpy/core/tests/test_numeric.py | 51 | ||||
-rw-r--r-- | numpy/core/tests/test_umath.py | 7 |
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) |