[Numpy-svn] r5954 - in trunk/numpy/core: code_generators src tests
numpy-svn at scipy.org
numpy-svn at scipy.org
Tue Oct 21 16:13:22 EDT 2008
Author: charris
Date: 2008-10-21 15:13:17 -0500 (Tue, 21 Oct 2008)
New Revision: 5954
Modified:
trunk/numpy/core/code_generators/generate_umath.py
trunk/numpy/core/src/umathmodule.c.src
trunk/numpy/core/tests/test_umath.py
Log:
Change way maximum and minimum deal with nans.
Add ufuncs fmax and fmin.
In the following, a complex number is considered a nan if the real or imaginary
part is nan. This means that there are many different complex numbers that are
nans and this effects the nan values returned by the maximum, minimum, fmax, and
fmin ufuncs.
The maximum and minimum ufuncs are the same as before unless nans are involved.
In the case of nans, if both values being compared are nans, then the first is
returned, otherwise the nan value is returned. This has the effect of
propagating nans.
The fmax and fmin ufuncs return the same values as maximum and minimum if
neither value being compared is nan. In the case of nans, if both values being
compared are nans, then the first is returned, otherwise the non-nan value is
returned. This has the effect that nans are ignored unless both values are nan.
Modified: trunk/numpy/core/code_generators/generate_umath.py
===================================================================
--- trunk/numpy/core/code_generators/generate_umath.py 2008-10-21 04:49:44 UTC (rev 5953)
+++ trunk/numpy/core/code_generators/generate_umath.py 2008-10-21 20:13:17 UTC (rev 5954)
@@ -316,6 +316,16 @@
TD(noobj),
TD(O, f='_npy_ObjectMin')
),
+'fmax' :
+ Ufunc(2, 1, None,
+ "",
+ TD(inexact)
+ ),
+'fmin' :
+ Ufunc(2, 1, None,
+ "",
+ TD(inexact)
+ ),
'bitwise_and' :
Ufunc(2, 1, One,
docstrings.get('numpy.core.umath.bitwise_and'),
Modified: trunk/numpy/core/src/umathmodule.c.src
===================================================================
--- trunk/numpy/core/src/umathmodule.c.src 2008-10-21 04:49:44 UTC (rev 5953)
+++ trunk/numpy/core/src/umathmodule.c.src 2008-10-21 20:13:17 UTC (rev 5954)
@@ -654,7 +654,7 @@
{
UNARY_LOOP {
const @s@@type@ in1 = *(@s@@type@ *)ip1;
- *((@s@@type@ *)op) = 1.0/in1;
+ *((@s@@type@ *)op) = (@s@@type@)(1.0/in1);
}
}
@@ -924,6 +924,9 @@
* #C = F, , L#
*/
+#define ONE 1.0 at c@
+#define ZERO 0.0 at c@
+
/**begin repeat1
* Arithmetic
* # kind = add, subtract, multiply, divide#
@@ -991,7 +994,7 @@
/**begin repeat1
* #kind = maximum, minimum#
- * #OP = >, <#
+ * #OP = >=, <=#
**/
static void
@TYPE at _@kind@(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func))
@@ -1000,12 +1003,28 @@
BINARY_LOOP {
const @type@ in1 = *(@type@ *)ip1;
const @type@ in2 = *(@type@ *)ip2;
- *((@type@ *)op) = in1 @OP@ in2 ? in1 : in2;
+ *((@type@ *)op) = (in1 @OP@ in2 || isnan(in1)) ? in1 : in2;
}
}
/**end repeat1**/
+/**begin repeat1
+ * #kind = fmax, fmin#
+ * #OP = >=, <=#
+ **/
static void
+ at TYPE@_ at kind@(char **args, intp *dimensions, intp *steps, void *func)
+{
+ /* */
+ BINARY_LOOP {
+ const @type@ in1 = *(@type@ *)ip1;
+ const @type@ in2 = *(@type@ *)ip2;
+ *((@type@ *)op) = (in1 @OP@ in2 || isnan(in2)) ? in1 : in2;
+ }
+}
+/**end repeat1**/
+
+static void
@TYPE at _floor_divide(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func))
{
BINARY_LOOP {
@@ -1045,7 +1064,7 @@
{
UNARY_LOOP {
const @type@ in1 = *(@type@ *)ip1;
- *((@type@ *)op) = 1.0/in1;
+ *((@type@ *)op) = ONE/in1;
}
}
@@ -1053,7 +1072,7 @@
@TYPE at _ones_like(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(data))
{
OUTPUT_LOOP {
- *((@type@ *)op) = 1;
+ *((@type@ *)op) = ONE;
}
}
@@ -1071,7 +1090,7 @@
{
UNARY_LOOP {
const @type@ in1 = *(@type@ *)ip1;
- const @type@ tmp = (in1 > 0) ? in1 : -in1;
+ const @type@ tmp = in1 > 0 ? in1 : -in1;
/* add 0 to clear -0.0 */
*((@type@ *)op) = tmp + 0;
}
@@ -1138,6 +1157,9 @@
#define @TYPE at _true_divide @TYPE at _divide
+#undef ONE
+#undef ZERO
+
/**end repeat**/
@@ -1155,6 +1177,11 @@
* #c = f, , l#
*/
+#define CGE(xr,xi,yr,yi) (xr > yr || (xr == yr && xi >= yi))
+#define CLE(xr,xi,yr,yi) (xr < yr || (xr == yr && xi <= yi))
+#define ONE 1.0 at c@
+#define ZERO 0.0 at c@
+
/**begin repeat1
* arithmetic
* #kind = add, subtract#
@@ -1348,8 +1375,8 @@
@CTYPE at _ones_like(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(data))
{
OUTPUT_LOOP {
- ((@type@ *)op)[0] = 1;
- ((@type@ *)op)[1] = 0;
+ ((@type@ *)op)[0] = ONE;
+ ((@type@ *)op)[1] = ZERO;
}
}
@@ -1380,29 +1407,30 @@
const @type@ in1r = ((@type@ *)ip1)[0];
const @type@ in1i = ((@type@ *)ip1)[1];
if (in1r > 0) {
- ((@type@ *)op)[0] = 1;
+ ((@type@ *)op)[0] = ONE;
}
else if (in1r < 0) {
- ((@type@ *)op)[0] = -1;
+ ((@type@ *)op)[0] = -ONE;
}
else {
if (in1i > 0) {
- ((@type@ *)op)[0] = 1;
+ ((@type@ *)op)[0] = ONE;
}
else if (in1i < 0) {
- ((@type@ *)op)[0] = -1;
+ ((@type@ *)op)[0] = -ONE;
}
else {
- ((@type@ *)op)[0] = 0;
+ ((@type@ *)op)[0] = ZERO;
}
}
- ((@type@ *)op)[1] = 0;
+ ((@type@ *)op)[1] = ZERO;
}
}
/**begin repeat1
* #kind = maximum, minimum#
- * #OP = >, <#
+ * #OP1 = CGE, CLE#
+ * #OP2 = CLE, CGE#
*/
static void
@CTYPE at _@kind@(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func))
@@ -1412,7 +1440,7 @@
const @type@ in1i = ((@type@ *)ip1)[1];
const @type@ in2r = ((@type@ *)ip2)[0];
const @type@ in2i = ((@type@ *)ip2)[1];
- if (in1r @OP@ in2r || ((in1r == in2r) && (in1i @OP@ in2i))) {
+ if (@OP1@(in1r, in1i, in2r, in2i) || isnan(in1r) || isnan(in1i)) {
((@type@ *)op)[0] = in1r;
((@type@ *)op)[1] = in1i;
}
@@ -1424,7 +1452,37 @@
}
/**end repeat1**/
+/**begin repeat1
+ * #kind = fmax, fmin#
+ * #OP1 = CGE, CLE#
+ */
+static void
+ at CTYPE@_ at kind@(char **args, intp *dimensions, intp *steps, void *func)
+{
+ BINARY_LOOP {
+ const @type@ in1r = ((@type@ *)ip1)[0];
+ const @type@ in1i = ((@type@ *)ip1)[1];
+ const @type@ in2r = ((@type@ *)ip2)[0];
+ const @type@ in2i = ((@type@ *)ip2)[1];
+ if (@OP1@(in1r, in1i, in2r, in2i) || isnan(in2r) || isnan(in2i)) {
+ ((@type@ *)op)[0] = in1r;
+ ((@type@ *)op)[1] = in1i;
+ }
+ else {
+ ((@type@ *)op)[0] = in2r;
+ ((@type@ *)op)[1] = in2i;
+ }
+ }
+}
+/**end repeat1**/
+
#define @CTYPE at _true_divide @CTYPE at _divide
+
+#undef CGE
+#undef CLE
+#undef ONE
+#undef ZERO
+
/**end repeat**/
/*
@@ -1447,6 +1505,7 @@
}
/**end repeat**/
+static void
OBJECT_sign(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func))
{
PyObject *zero = PyInt_FromLong(0);
@@ -1464,6 +1523,16 @@
*/
+/*
+ *****************************************************************************
+ ** SETUP UFUNCS **
+ *****************************************************************************
+ */
+
+#include "__umath_generated.c"
+#include "ufuncobject.c"
+#include "__ufunc_api.c"
+
static PyUFuncGenericFunction frexp_functions[] = {
#ifdef HAVE_FREXPF
FLOAT_frexp,
@@ -1485,7 +1554,6 @@
#endif
};
-
static PyUFuncGenericFunction ldexp_functions[] = {
#ifdef HAVE_LDEXPF
FLOAT_ldexp,
@@ -1507,10 +1575,6 @@
};
-#include "__umath_generated.c"
-#include "ufuncobject.c"
-#include "__ufunc_api.c"
-
static double
pinf_init(void)
{
Modified: trunk/numpy/core/tests/test_umath.py
===================================================================
--- trunk/numpy/core/tests/test_umath.py 2008-10-21 04:49:44 UTC (rev 5953)
+++ trunk/numpy/core/tests/test_umath.py 2008-10-21 20:13:17 UTC (rev 5954)
@@ -47,13 +47,84 @@
class TestMaximum(TestCase):
def test_reduce_complex(self):
- assert_equal(ncu.maximum.reduce([1,2j]),1)
- assert_equal(ncu.maximum.reduce([1+3j,2j]),1+3j)
+ assert_equal(np.maximum.reduce([1,2j]),1)
+ assert_equal(np.maximum.reduce([1+3j,2j]),1+3j)
+ def test_float_nans(self):
+ nan = np.nan
+ arg1 = np.array([0, nan, nan])
+ arg2 = np.array([nan, 0, nan])
+ out = np.array([nan, nan, nan])
+ assert_equal(np.maximum(arg1, arg2), out)
+
+ def test_complex_nans(self):
+ nan = np.nan
+ for cnan in [nan, nan*1j, nan + nan*1j] :
+ arg1 = np.array([0, cnan, cnan], dtype=np.complex)
+ arg2 = np.array([cnan, 0, cnan], dtype=np.complex)
+ out = np.array([nan, nan, nan], dtype=np.complex)
+ assert_equal(np.maximum(arg1, arg2), out)
+
class TestMinimum(TestCase):
def test_reduce_complex(self):
- assert_equal(ncu.minimum.reduce([1,2j]),2j)
+ assert_equal(np.minimum.reduce([1,2j]),2j)
+ assert_equal(np.minimum.reduce([1+3j,2j]),2j)
+ def test_float_nans(self):
+ nan = np.nan
+ arg1 = np.array([0, nan, nan])
+ arg2 = np.array([nan, 0, nan])
+ out = np.array([nan, nan, nan])
+ assert_equal(np.minimum(arg1, arg2), out)
+
+ def test_complex_nans(self):
+ nan = np.nan
+ for cnan in [nan, nan*1j, nan + nan*1j] :
+ arg1 = np.array([0, cnan, cnan], dtype=np.complex)
+ arg2 = np.array([cnan, 0, cnan], dtype=np.complex)
+ out = np.array([nan, nan, nan], dtype=np.complex)
+ assert_equal(np.minimum(arg1, arg2), out)
+
+class TestFmax(TestCase):
+ def test_reduce_complex(self):
+ assert_equal(np.fmax.reduce([1,2j]),1)
+ assert_equal(np.fmax.reduce([1+3j,2j]),1+3j)
+
+ def test_float_nans(self):
+ nan = np.nan
+ arg1 = np.array([0, nan, nan])
+ arg2 = np.array([nan, 0, nan])
+ out = np.array([0, 0, nan])
+ assert_equal(np.fmax(arg1, arg2), out)
+
+ def test_complex_nans(self):
+ nan = np.nan
+ for cnan in [nan, nan*1j, nan + nan*1j] :
+ arg1 = np.array([0, cnan, cnan], dtype=np.complex)
+ arg2 = np.array([cnan, 0, cnan], dtype=np.complex)
+ out = np.array([0, 0, nan], dtype=np.complex)
+ assert_equal(np.fmax(arg1, arg2), out)
+
+class TestFmin(TestCase):
+ def test_reduce_complex(self):
+ assert_equal(np.fmin.reduce([1,2j]),2j)
+ assert_equal(np.fmin.reduce([1+3j,2j]),2j)
+
+ def test_float_nans(self):
+ nan = np.nan
+ arg1 = np.array([0, nan, nan])
+ arg2 = np.array([nan, 0, nan])
+ out = np.array([0, 0, nan])
+ assert_equal(np.fmin(arg1, arg2), out)
+
+ def test_complex_nans(self):
+ nan = np.nan
+ for cnan in [nan, nan*1j, nan + nan*1j] :
+ arg1 = np.array([0, cnan, cnan], dtype=np.complex)
+ arg2 = np.array([cnan, 0, cnan], dtype=np.complex)
+ out = np.array([0, 0, nan], dtype=np.complex)
+ assert_equal(np.fmin(arg1, arg2), out)
+
class TestFloatingPoint(TestCase):
def test_floating_point(self):
assert_equal(ncu.FLOATING_POINT_SUPPORT, 1)
More information about the Numpy-svn
mailing list