diff options
author | Mark Wiebe <mwiebe@enthought.com> | 2011-06-16 14:49:56 -0500 |
---|---|---|
committer | Mark Wiebe <mwiebe@enthought.com> | 2011-06-16 14:49:56 -0500 |
commit | 2d7d59aef203ebf25b268ceaccfa1be45237b0df (patch) | |
tree | 5a9da14c4577a9d0558045be4b9a49d56b94b26c | |
parent | e9f4e7592ae24e220bfcd0489b4bb25b9c2fc8e7 (diff) | |
download | numpy-2d7d59aef203ebf25b268ceaccfa1be45237b0df.tar.gz |
ENH: datetime-ufunc: Add m8 / m8 -> f8 case to the datetime ufunc operations
-rw-r--r-- | numpy/core/code_generators/generate_umath.py | 1 | ||||
-rw-r--r-- | numpy/core/src/umath/loops.c.src | 15 | ||||
-rw-r--r-- | numpy/core/src/umath/loops.h | 15 | ||||
-rw-r--r-- | numpy/core/src/umath/loops.h.src | 3 | ||||
-rw-r--r-- | numpy/core/src/umath/ufunc_object.c | 30 | ||||
-rw-r--r-- | numpy/core/tests/test_datetime.py | 16 |
6 files changed, 65 insertions, 15 deletions
diff --git a/numpy/core/code_generators/generate_umath.py b/numpy/core/code_generators/generate_umath.py index 599ffddc8..957607f40 100644 --- a/numpy/core/code_generators/generate_umath.py +++ b/numpy/core/code_generators/generate_umath.py @@ -275,6 +275,7 @@ defdict = { TD(intfltcmplx), [TypeDescription('m', FullTypeDescr, 'mq', 'm'), TypeDescription('m', FullTypeDescr, 'md', 'm'), + TypeDescription('m', FullTypeDescr, 'mm', 'd'), ], TD(O, f='PyNumber_Divide'), ), diff --git a/numpy/core/src/umath/loops.c.src b/numpy/core/src/umath/loops.c.src index 31345ff45..b23f1018c 100644 --- a/numpy/core/src/umath/loops.c.src +++ b/numpy/core/src/umath/loops.c.src @@ -1229,6 +1229,21 @@ TIMEDELTA_md_m_divide(char **args, intp *dimensions, intp *steps, void *NPY_UNUS } } +NPY_NO_EXPORT void +TIMEDELTA_mm_d_divide(char **args, intp *dimensions, 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) { + *((double *)op1) = NPY_NAN; + } + else { + *((double *)op1) = (double)in1 / (double)in2; + } + } +} + /* ***************************************************************************** ** FLOAT LOOPS ** diff --git a/numpy/core/src/umath/loops.h b/numpy/core/src/umath/loops.h index 2a827e168..2a792bf5b 100644 --- a/numpy/core/src/umath/loops.h +++ b/numpy/core/src/umath/loops.h @@ -2661,6 +2661,9 @@ TIMEDELTA_mq_m_divide(char **args, intp *dimensions, intp *steps, void *NPY_UNUS NPY_NO_EXPORT void TIMEDELTA_md_m_divide(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); +NPY_NO_EXPORT void +TIMEDELTA_mm_d_divide(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); + /* Special case equivalents to above functions */ #define TIMEDELTA_mq_m_true_divide TIMEDELTA_mq_m_divide @@ -2678,27 +2681,27 @@ TIMEDELTA_md_m_divide(char **args, intp *dimensions, intp *steps, void *NPY_UNUS ***************************************************************************** */ -#line 511 +#line 514 NPY_NO_EXPORT void OBJECT_equal(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 511 +#line 514 NPY_NO_EXPORT void OBJECT_not_equal(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 511 +#line 514 NPY_NO_EXPORT void OBJECT_greater(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 511 +#line 514 NPY_NO_EXPORT void OBJECT_greater_equal(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 511 +#line 514 NPY_NO_EXPORT void OBJECT_less(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); -#line 511 +#line 514 NPY_NO_EXPORT void OBJECT_less_equal(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); diff --git a/numpy/core/src/umath/loops.h.src b/numpy/core/src/umath/loops.h.src index bf41e4187..fdedc1933 100644 --- a/numpy/core/src/umath/loops.h.src +++ b/numpy/core/src/umath/loops.h.src @@ -487,6 +487,9 @@ TIMEDELTA_mq_m_divide(char **args, intp *dimensions, intp *steps, void *NPY_UNUS NPY_NO_EXPORT void TIMEDELTA_md_m_divide(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); +NPY_NO_EXPORT void +TIMEDELTA_mm_d_divide(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)); + /* Special case equivalents to above functions */ #define TIMEDELTA_mq_m_true_divide TIMEDELTA_mq_m_divide diff --git a/numpy/core/src/umath/ufunc_object.c b/numpy/core/src/umath/ufunc_object.c index 2e46fc51a..dcc29f2ba 100644 --- a/numpy/core/src/umath/ufunc_object.c +++ b/numpy/core/src/umath/ufunc_object.c @@ -2822,8 +2822,9 @@ type_reso_error: { /* * This function applies the type resolution rules for division. * In particular, there are a number of special cases with datetime: - * m8[<A>] / int## => m8[<A>] / int64 - * m8[<A>] / float## => m8[<A>] / float64 + * m8[<A>] / m8[<B>] to m8[gcd(<A>,<B>)] / m8[gcd(<A>,<B>)] -> float64 + * m8[<A>] / int## to m8[<A>] / int64 -> m8[<A>] + * m8[<A>] / float## to m8[<A>] / float64 -> m8[<A>] */ NPY_NO_EXPORT int PyUFunc_DivisionTypeResolution(PyUFuncObject *ufunc, @@ -2851,13 +2852,34 @@ PyUFunc_DivisionTypeResolution(PyUFuncObject *ufunc, } if (type_num1 == NPY_TIMEDELTA) { + /* + * m8[<A>] / m8[<B>] to + * m8[gcd(<A>,<B>)] / m8[gcd(<A>,<B>)] -> float64 + */ + if (type_num2 == NPY_TIMEDELTA) { + out_dtypes[0] = PyArray_PromoteTypes(PyArray_DESCR(operands[0]), + PyArray_DESCR(operands[1])); + if (out_dtypes[0] == NULL) { + return -1; + } + out_dtypes[1] = out_dtypes[0]; + Py_INCREF(out_dtypes[1]); + out_dtypes[2] = PyArray_DescrFromType(NPY_DOUBLE); + if (out_dtypes[2] == NULL) { + Py_DECREF(out_dtypes[0]); + out_dtypes[0] = NULL; + Py_DECREF(out_dtypes[1]); + out_dtypes[1] = NULL; + return -1; + } + } /* m8[<A>] / int## => m8[<A>] / int64 */ - if (PyTypeNum_ISINTEGER(type_num2)) { + else if (PyTypeNum_ISINTEGER(type_num2)) { out_dtypes[0] = ensure_dtype_nbo(PyArray_DESCR(operands[0])); if (out_dtypes[0] == NULL) { return -1; } - out_dtypes[1] = PyArray_DescrNewFromType(NPY_LONGLONG); + out_dtypes[1] = PyArray_DescrFromType(NPY_LONGLONG); if (out_dtypes[1] == 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 b51febb85..c533f3b2c 100644 --- a/numpy/core/tests/test_datetime.py +++ b/numpy/core/tests/test_datetime.py @@ -738,31 +738,37 @@ class TestDateTime(TestCase): assert_raises(TypeError, np.multiply, 1.5, dta) def test_datetime_divide(self): - for dta, tda, tdb, tdc in \ + for dta, tda, tdb, tdc, tdd in \ [ # One-dimensional arrays (np.array(['2012-12-21'], dtype='M8[D]'), np.array([6], dtype='m8[h]'), np.array([9], dtype='m8[h]'), - np.array([12], dtype='m8[h]')), + np.array([12], dtype='m8[h]'), + np.array([6], dtype='m8[m]')), # NumPy scalars (np.datetime64('2012-12-21', '[D]'), np.timedelta64(6, '[h]'), np.timedelta64(9, '[h]'), - np.timedelta64(12, '[h]'))]: + np.timedelta64(12, '[h]'), + np.timedelta64(6, '[m]'))]: # m8 / int assert_equal(tdc / 2, tda) assert_equal((tdc / 2).dtype, np.dtype('m8[h]')) # m8 / float assert_equal(tda / 0.5, tdc) assert_equal((tda / 0.5).dtype, np.dtype('m8[h]')) + # m8 / m8 + assert_equal(tda / tdb, 6.0 / 9.0) + assert_equal(tdb / tda, 9.0 / 6.0) + assert_equal((tda / tdb).dtype, np.dtype('f8')) + assert_equal(tda / tdd, 60.0) + assert_equal(tdd / tda, 1.0 / 60.0) # int / m8 assert_raises(TypeError, np.divide, 2, tdb) # float / m8 assert_raises(TypeError, np.divide, 0.5, tdb) - # m8 / m8 - assert_raises(TypeError, np.divide, tda, tdb) # m8 / M8 assert_raises(TypeError, np.divide, dta, tda) # M8 / m8 |