Skip to content

Commit 9b071c2

Browse files
authored
Merge pull request #536 from pydata/fix_funcbugs
Fix funcbugs
2 parents f360f12 + 780908a commit 9b071c2

File tree

6 files changed

+127
-50
lines changed

6 files changed

+127
-50
lines changed

numexpr/bespoke_functions.hpp

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,51 @@ inline long fabsl(long x) {return x<0 ? -x: x;}
3535
// inline long fmodl(long x, long y) {return (long)fmodf((long)x, (long)y);}
3636

3737
#ifdef USE_VML
38+
// To match Numpy behaviour for NaNs
39+
static void vsFmax_(MKL_INT n, const float* x1, const float* x2, float* dest)
40+
{
41+
vsFmax(n, x1, x2, dest);
42+
MKL_INT j;
43+
for (j=0; j<n; j++) {
44+
if (isnanf_(x1[j]) | isnanf_(x2[j])){
45+
dest[j] = NAN;
46+
}
47+
};
48+
};
49+
50+
static void vsFmin_(MKL_INT n, const float* x1, const float* x2, float* dest)
51+
{
52+
vsFmin(n, x1, x2, dest);
53+
MKL_INT j;
54+
for (j=0; j<n; j++) {
55+
if (isnanf_(x1[j]) | isnanf_(x2[j])){
56+
dest[j] = NAN;
57+
}
58+
};
59+
};
60+
// To match Numpy behaviour for NaNs
61+
static void vdFmax_(MKL_INT n, const double* x1, const double* x2, double* dest)
62+
{
63+
vdFmax(n, x1, x2, dest);
64+
MKL_INT j;
65+
for (j=0; j<n; j++) {
66+
if (isnand(x1[j]) | isnand(x2[j])){
67+
dest[j] = NAN;
68+
}
69+
};
70+
};
71+
72+
static void vdFmin_(MKL_INT n, const double* x1, const double* x2, double* dest)
73+
{
74+
vdFmin(n, x1, x2, dest);
75+
MKL_INT j;
76+
for (j=0; j<n; j++) {
77+
if (isnand(x1[j]) | isnand(x2[j])){
78+
dest[j] = NAN;
79+
}
80+
};
81+
};
82+
3883
static void viRint(MKL_INT n, const int* x, int* dest)
3984
{
4085
memcpy(dest, x, n * sizeof(int)); // just copy x1 which is already int

numexpr/expressions.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -531,6 +531,9 @@ class OpNode(ExpressionNode):
531531
def __init__(self, opcode=None, args=None, kind=None):
532532
if (kind is None) and (args is not None):
533533
kind = commonKind(args)
534+
if kind=='bool': # handle bool*bool and bool+bool cases
535+
opcode = 'and' if opcode=='mul' else opcode
536+
opcode = 'or' if opcode=='add' else opcode
534537
ExpressionNode.__init__(self, value=opcode, kind=kind, children=args)
535538

536539

numexpr/functions.hpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -56,8 +56,8 @@ FUNC_FFF(FUNC_ARCTAN2_FFF, "arctan2_fff", atan2f, atan2f2, vsAtan2)
5656
FUNC_FFF(FUNC_HYPOT_FFF, "hypot_fff", hypotf, hypotf2, vsHypot)
5757
FUNC_FFF(FUNC_NEXTAFTER_FFF, "nextafter_fff", nextafterf, nextafterf2, vsNextAfter)
5858
FUNC_FFF(FUNC_COPYSIGN_FFF, "copysign_fff", copysignf, copysignf2, vsCopySign)
59-
FUNC_FFF(FUNC_MAXIMUM_FFF, "maximum_fff", fmaxf, fmaxf2, vsFmax)
60-
FUNC_FFF(FUNC_MINIMUM_FFF, "minimum_fff", fminf, fminf2, vsFmin)
59+
FUNC_FFF(FUNC_MAXIMUM_FFF, "maximum_fff", fmaxf_, fmaxf2, vsFmax_)
60+
FUNC_FFF(FUNC_MINIMUM_FFF, "minimum_fff", fminf_, fminf2, vsFmin_)
6161
FUNC_FFF(FUNC_FFF_LAST, NULL, NULL, NULL, NULL)
6262
#ifdef ELIDE_FUNC_FFF
6363
#undef ELIDE_FUNC_FFF
@@ -140,8 +140,8 @@ FUNC_DDD(FUNC_ARCTAN2_DDD, "arctan2_ddd", atan2, vdAtan2)
140140
FUNC_DDD(FUNC_HYPOT_DDD, "hypot_ddd", hypot, vdHypot)
141141
FUNC_DDD(FUNC_NEXTAFTER_DDD, "nextafter_ddd", nextafter, vdNextAfter)
142142
FUNC_DDD(FUNC_COPYSIGN_DDD, "copysign_ddd", copysign, vdCopySign)
143-
FUNC_DDD(FUNC_MAXIMUM_DDD, "maximum_ddd", fmaxd, vdFmax)
144-
FUNC_DDD(FUNC_MINIMUM_DDD, "minimum_ddd", fmind, vdFmin)
143+
FUNC_DDD(FUNC_MAXIMUM_DDD, "maximum_ddd", fmaxd, vdFmax_)
144+
FUNC_DDD(FUNC_MINIMUM_DDD, "minimum_ddd", fmind, vdFmin_)
145145
FUNC_DDD(FUNC_DDD_LAST, NULL, NULL, NULL)
146146
#ifdef ELIDE_FUNC_DDD
147147
#undef ELIDE_FUNC_DDD

numexpr/msvc_function_stubs.hpp

Lines changed: 53 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -16,47 +16,6 @@
1616
definitions in <math.h> are actually #define'd and are not usable
1717
as function pointers :-/ */
1818

19-
#if _MSC_VER < 1400 // 1310 == MSVC 7.1
20-
/* Apparently, single precision functions are not included in MSVC 7.1 */
21-
22-
#define sqrtf(x) ((float)sqrt((double)(x)))
23-
#define sinf(x) ((float)sin((double)(x)))
24-
#define cosf(x) ((float)cos((double)(x)))
25-
#define tanf(x) ((float)tan((double)(x)))
26-
#define asinf(x) ((float)asin((double)(x)))
27-
#define acosf(x) ((float)acos((double)(x)))
28-
#define atanf(x) ((float)atan((double)(x)))
29-
#define sinhf(x) ((float)sinh((double)(x)))
30-
#define coshf(x) ((float)cosh((double)(x)))
31-
#define tanhf(x) ((float)tanh((double)(x)))
32-
#define asinhf(x) ((float)asinh((double)(x)))
33-
#define acoshf(x) ((float)acosh((double)(x)))
34-
#define atanhf(x) ((float)atanh((double)(x)))
35-
#define logf(x) ((float)log((double)(x)))
36-
#define log1pf(x) ((float)log1p((double)(x)))
37-
#define log10f(x) ((float)log10((double)(x)))
38-
#define log2f(x) ((float)log2((double)(x)))
39-
#define expf(x) ((float)exp((double)(x)))
40-
#define expm1f(x) ((float)expm1((double)(x)))
41-
#define fabsf(x) ((float)fabs((double)(x)))
42-
#define fmodf(x, y) ((float)fmod((double)(x), (double)(y)))
43-
#define atan2f(x, y) ((float)atan2((double)(x), (double)(y)))
44-
#define hypotf(x, y) ((float)hypot((double)(x), (double)(y)))
45-
#define copysignf(x, y) ((float)copysign((double)(x), (double)(y)))
46-
#define nextafterf(x, y) ((float)nextafter((double)(x), (double)(y)))
47-
#define fmaxf(x, y) ((float)fmaxd((double)(x), (double)(y)))
48-
#define fminf(x, y) ((float)fmind((double)(x), (double)(y)))
49-
#define ceilf(x) ((float)ceil((double)(x)))
50-
#define hypotf(x) ((float)hypot((double)(x)))
51-
#define rintf(x) ((float)rint((double)(x)))
52-
#define truncf(x) ((float)trunc((double)(x)))
53-
54-
55-
/* The next are directly called from interp_body.cpp */
56-
#define powf(x, y) ((float)pow((double)(x), (double)(y)))
57-
#define floorf(x) ((float)floor((double)(x)))
58-
#endif // _MSC_VER < 1400
59-
6019
/* Due to casting problems (normally return ints not bools, easiest to define
6120
non-overloaded wrappers for these functions) */
6221
// MSVC version: use global ::isfinite / ::isnan
@@ -67,6 +26,57 @@ inline bool isnand(double x) { return !!::_isnan(x); }
6726
inline bool isinfd(double x) { return !!::isinf(x); }
6827
inline bool isinff_(float x) { return !!::isinf(x); }
6928

29+
// To handle overloading of fmax/fmin in cmath and match NumPy behaviour for NaNs
30+
inline double fmaxd(double x, double y) { return (isnand(x) | isnand(y))? NAN : fmax(x, y); }
31+
inline double fmind(double x, double y) { return (isnand(x) | isnand(y))? NAN : fmin(x, y); }
32+
33+
34+
#if _MSC_VER < 1400 // 1310 == MSVC 7.1
35+
/* Apparently, single precision functions are not included in MSVC 7.1 */
36+
37+
#define sqrtf(x) ((float)sqrt((double)(x)))
38+
#define sinf(x) ((float)sin((double)(x)))
39+
#define cosf(x) ((float)cos((double)(x)))
40+
#define tanf(x) ((float)tan((double)(x)))
41+
#define asinf(x) ((float)asin((double)(x)))
42+
#define acosf(x) ((float)acos((double)(x)))
43+
#define atanf(x) ((float)atan((double)(x)))
44+
#define sinhf(x) ((float)sinh((double)(x)))
45+
#define coshf(x) ((float)cosh((double)(x)))
46+
#define tanhf(x) ((float)tanh((double)(x)))
47+
#define asinhf(x) ((float)asinh((double)(x)))
48+
#define acoshf(x) ((float)acosh((double)(x)))
49+
#define atanhf(x) ((float)atanh((double)(x)))
50+
#define logf(x) ((float)log((double)(x)))
51+
#define log1pf(x) ((float)log1p((double)(x)))
52+
#define log10f(x) ((float)log10((double)(x)))
53+
#define log2f(x) ((float)log2((double)(x)))
54+
#define expf(x) ((float)exp((double)(x)))
55+
#define expm1f(x) ((float)expm1((double)(x)))
56+
#define fabsf(x) ((float)fabs((double)(x)))
57+
#define fmodf(x, y) ((float)fmod((double)(x), (double)(y)))
58+
#define atan2f(x, y) ((float)atan2((double)(x), (double)(y)))
59+
#define hypotf(x, y) ((float)hypot((double)(x), (double)(y)))
60+
#define copysignf(x, y) ((float)copysign((double)(x), (double)(y)))
61+
#define nextafterf(x, y) ((float)nextafter((double)(x), (double)(y)))
62+
#define ceilf(x) ((float)ceil((double)(x)))
63+
#define hypotf(x) ((float)hypot((double)(x)))
64+
#define rintf(x) ((float)rint((double)(x)))
65+
#define truncf(x) ((float)trunc((double)(x)))
66+
67+
68+
/* The next are directly called from interp_body.cpp */
69+
#define powf(x, y) ((float)pow((double)(x), (double)(y)))
70+
#define floorf(x) ((float)floor((double)(x)))
71+
72+
#define fmaxf_(x, y) ((float)fmaxd((double)(x), (double)(y))) // define fmaxf_ since fmaxf doesn't exist for early MSVC
73+
#define fminf_(x, y) ((float)fmind((double)(x), (double)(y)))
74+
#else
75+
inline float fmaxf_(float x, float y) { return (isnanf_(x) | isnanf_(y))? NAN : fmaxf(x, y); }
76+
inline float fminf_(float x, float y) { return (isnanf_(x) | isnanf_(y))? NAN : fminf(x, y); }
77+
#endif // _MSC_VER < 1400
78+
79+
7080
/* Now the actual stubs */
7181

7282
inline float sqrtf2(float x) {
@@ -170,11 +180,11 @@ inline float copysignf2(float x, float y) {
170180
}
171181

172182
inline float fmaxf2(float x, float y) {
173-
return fmaxf(x, y);
183+
return fmaxf_(x, y);
174184
}
175185

176186
inline float fminf2(float x, float y) {
177-
return fminf(x, y);
187+
return fminf_(x, y);
178188
}
179189

180190

numexpr/numexpr_config.hpp

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -43,9 +43,7 @@
4343
#include <cmath>
4444
//no single precision version of signbit in C++ standard
4545
inline bool signbitf(float x) { return signbit((double)x); }
46-
// To handle overloading of fmax/fmin in cmath
47-
inline double fmaxd(double x, double y) { return fmax(x, y); }
48-
inline double fmind(double x, double y) { return fmin(x, y); }
46+
4947
#ifdef _WIN32
5048
#ifndef __MINGW32__
5149
#include "missing_posix_functions.hpp"
@@ -62,6 +60,12 @@ inline bool isfinited(double x) { return !!std::isfinite(x); }
6260
inline bool isnand(double x) { return !!std::isnan(x); }
6361
inline bool isinff_(float x) { return !!std::isinf(x); }
6462
inline bool isinfd(double x) { return !!std::isinf(x); }
63+
64+
// To handle overloading of fmax/fmin in cmath and match NumPy behaviour for NaNs
65+
inline double fmaxd(double x, double y) { return (isnand(x) | isnand(y))? NAN : fmax(x, y); }
66+
inline double fmind(double x, double y) { return (isnand(x) | isnand(y))? NAN : fmin(x, y); }
67+
inline float fmaxf_(float x, float y) { return (isnanf_(x) | isnanf_(y))? NAN : fmaxf(x, y); }
68+
inline float fminf_(float x, float y) { return (isnanf_(x) | isnanf_(y))? NAN : fminf(x, y); }
6569
#endif
6670

6771
#endif // NUMEXPR_CONFIG_HPP

numexpr/tests/test_numexpr.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -484,9 +484,24 @@ def test_maximum_minimum(self):
484484
for dtype in [float, double, int, np.int64]:
485485
x = arange(10, dtype=dtype)
486486
y = 2 * arange(10, dtype=dtype)[::-1]
487+
if dtype in (float, double):
488+
y[5] = np.nan
489+
x[2] = np.nan
487490
assert_array_equal(evaluate("maximum(x,y)"), maximum(x,y))
488491
assert_array_equal(evaluate("minimum(x,y)"), minimum(x,y))
489492

493+
def test_addmult_booleans(self):
494+
x = np.asarray([0, 1, 0, 0, 1], dtype=bool)
495+
y = x[::-1]
496+
res_ne = evaluate("x * y")
497+
res_np = x * y
498+
assert_array_equal(res_ne, res_np)
499+
assert res_ne.dtype == res_np.dtype
500+
res_ne = evaluate("x + y")
501+
res_np = x + y
502+
assert_array_equal(res_ne, res_np)
503+
assert res_ne.dtype == res_np.dtype
504+
490505
def test_sign_round(self):
491506
for dtype in [float, double, np.int32, np.int64, complex]:
492507
x = arange(10, dtype=dtype)

0 commit comments

Comments
 (0)