Skip to content

Commit 996d56f

Browse files
committed
Added copysign, signbit
1 parent 616806a commit 996d56f

7 files changed

Lines changed: 66 additions & 27 deletions

File tree

numexpr/expressions.py

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -350,6 +350,7 @@ def multiply(x, y):
350350
'arctan2': func(numpy.arctan2, 'float'),
351351
'hypot': func(numpy.hypot, 'double'),
352352
'nextafter': func(numpy.nextafter, 'double'),
353+
'copysign': func(numpy.copysign, 'double'),
353354

354355
'log': func(numpy.log, 'float'),
355356
'log1p': func(numpy.log1p, 'float'),
@@ -371,9 +372,10 @@ def multiply(x, y):
371372
'complex': func(complex, 'complex'),
372373
'conj': func(numpy.conj, 'complex'),
373374

374-
'isnan': func(numpy.isnan, 'bool'),
375-
'isfinite': func(numpy.isfinite, 'bool'),
376-
'isinf': func(numpy.isinf, 'bool'),
375+
'isnan': func(numpy.isnan, 'double'),
376+
'isfinite': func(numpy.isfinite, 'double'),
377+
'isinf': func(numpy.isinf, 'double'),
378+
'signbit': func(numpy.signbit, 'double'),
377379

378380
'sum': gen_reduce_axis_func('sum'),
379381
'prod': gen_reduce_axis_func('prod'),
@@ -531,6 +533,6 @@ class FuncNode(OpNode):
531533
def __init__(self, opcode=None, args=None, kind=None):
532534
if (kind is None) and (args is not None):
533535
kind = commonKind(args)
534-
if opcode in ("isnan", "isfinite", "isinf"): # bodge for boolean return functions
536+
if opcode in ("isnan", "isfinite", "isinf", "signbit"): # bodge for boolean return functions
535537
kind = 'bool'
536538
OpNode.__init__(self, opcode, args, kind)

numexpr/functions.hpp

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ FUNC_FFF(FUNC_FMOD_FFF, "fmod_fff", fmodf, fmodf2, vsfmod)
5454
FUNC_FFF(FUNC_ARCTAN2_FFF, "arctan2_fff", atan2f, atan2f2, vsAtan2)
5555
FUNC_FFF(FUNC_HYPOT_FFF, "hypot_fff", hypotf, hypotf2, vsHypot)
5656
FUNC_FFF(FUNC_NEXTAFTER_FFF, "nextafter_fff", nextafterf, nextafterf2, vsNextAfter)
57+
FUNC_FFF(FUNC_COPYSIGN_FFF, "copysign_fff", copysignf, copysignf2, vsCopySign)
5758
FUNC_FFF(FUNC_FFF_LAST, NULL, NULL, NULL, NULL)
5859
#ifdef ELIDE_FUNC_FFF
5960
#undef ELIDE_FUNC_FFF
@@ -89,7 +90,7 @@ FUNC_DD(FUNC_CEIL_DD, "ceil_dd", ceil, vdCeil)
8990
FUNC_DD(FUNC_FLOOR_DD, "floor_dd", floor, vdFloor)
9091
FUNC_DD(FUNC_TRUNC_DD, "trunc_dd", trunc, vdTrunc)
9192
//rint rounds to nearest even integer, matching NumPy (round doesn't)
92-
FUNC_DD(FUNC_ROUND_DD, "round_dd", rint, vdRint)
93+
FUNC_DD(FUNC_ROUND_DD, "round_dd", rint, vdRint)
9394
FUNC_DD(FUNC_DD_LAST, NULL, NULL, NULL)
9495
#ifdef ELIDE_FUNC_DD
9596
#undef ELIDE_FUNC_DD
@@ -104,6 +105,7 @@ FUNC_DD(FUNC_DD_LAST, NULL, NULL, NULL)
104105
FUNC_BD(FUNC_ISNAN_BD, "isnan_bd", isnand, vdIsnan)
105106
FUNC_BD(FUNC_ISFINITE_BD, "isfinite_bd", isfinited, vdIsfinite)
106107
FUNC_BD(FUNC_ISINF_BD, "isinf_bd", isinfd, vdIsinf)
108+
FUNC_BD(FUNC_SIGNBIT_BD, "signbit_bd", signbit, vdSignBit)
107109
FUNC_BD(FUNC_BD_LAST, NULL, NULL, NULL)
108110
#ifdef ELIDE_FUNC_BD
109111
#undef ELIDE_FUNC_BD
@@ -115,9 +117,10 @@ FUNC_BD(FUNC_BD_LAST, NULL, NULL, NULL)
115117
#define ELIDE_FUNC_BF
116118
#define FUNC_BF(...)
117119
#endif // use wrappers as there is name collision with isnanf in std
118-
FUNC_BF(FUNC_ISNAN_BF, "isnan_bf", isnanf_, isnanf2, vfIsnan)
119-
FUNC_BF(FUNC_ISFINITE_BF, "isfinite_bf", isfinitef_, isfinitef2, vfIsfinite)
120-
FUNC_BF(FUNC_ISINF_BF, "isinf_bf", isinff_, isinff2, vfIsinf)
120+
FUNC_BF(FUNC_ISNAN_BF, "isnan_bf", isnanf_, isnanf2, vsIsnan)
121+
FUNC_BF(FUNC_ISFINITE_BF, "isfinite_bf", isfinitef_, isfinitef2, vsIsfinite)
122+
FUNC_BF(FUNC_ISINF_BF, "isinf_bf", isinff_, isinff2, vsIsinf)
123+
FUNC_BF(FUNC_SIGNBIT_BF, "signbit_bf", signbitf, signbitf2, vsSignBit)
121124
FUNC_BF(FUNC_BF_LAST, NULL, NULL, NULL, NULL)
122125
#ifdef ELIDE_FUNC_BF
123126
#undef ELIDE_FUNC_BF
@@ -132,6 +135,7 @@ FUNC_DDD(FUNC_FMOD_DDD, "fmod_ddd", fmod, vdfmod)
132135
FUNC_DDD(FUNC_ARCTAN2_DDD, "arctan2_ddd", atan2, vdAtan2)
133136
FUNC_DDD(FUNC_HYPOT_DDD, "hypot_ddd", hypot, vdHypot)
134137
FUNC_DDD(FUNC_NEXTAFTER_DDD, "nextafter_ddd", nextafter, vdNextAfter)
138+
FUNC_DDD(FUNC_COPYSIGN_DDD, "copysign_ddd", copysign, vdCopySign)
135139
FUNC_DDD(FUNC_DDD_LAST, NULL, NULL, NULL)
136140
#ifdef ELIDE_FUNC_DDD
137141
#undef ELIDE_FUNC_DDD

numexpr/interpreter.cpp

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -221,28 +221,35 @@ FuncBFPtr functions_bf[] = {
221221
#endif
222222

223223
#ifdef USE_VML
224-
/* no isnan, isfinite or isinf in VML */
225-
static void vfIsfinite(MKL_INT n, const float* x1, bool* dest)
224+
/* no isnan, isfinite, isinf or signbit in VML */
225+
static void vsIsfinite(MKL_INT n, const float* x1, bool* dest)
226226
{
227227
MKL_INT j;
228228
for (j=0; j<n; j++) {
229229
dest[j] = isfinitef_(x1[j]);
230230
};
231231
};
232-
static void vfIsinf(MKL_INT n, const float* x1, bool* dest)
232+
static void vsIsinf(MKL_INT n, const float* x1, bool* dest)
233233
{
234234
MKL_INT j;
235235
for (j=0; j<n; j++) {
236236
dest[j] = isinff_(x1[j]);
237237
};
238238
};
239-
static void vfIsnan(MKL_INT n, const float* x1, bool* dest)
239+
static void vsIsnan(MKL_INT n, const float* x1, bool* dest)
240240
{
241241
MKL_INT j;
242242
for (j=0; j<n; j++) {
243243
dest[j] = isnanf_(x1[j]);
244244
};
245245
};
246+
static void vsSignBit(MKL_INT n, const float* x1, bool* dest)
247+
{
248+
MKL_INT j;
249+
for (j=0; j<n; j++) {
250+
dest[j] = signbitf(x1[j]);
251+
};
252+
};
246253
#endif
247254

248255
#ifdef USE_VML
@@ -262,7 +269,7 @@ FuncBDPtr functions_bd[] = {
262269
};
263270

264271
#ifdef USE_VML
265-
/* no isnan, isfinite or isinf in VML */
272+
/* no isnan, isfinite, isinf, signbit in VML */
266273
static void vdIsfinite(MKL_INT n, const double* x1, bool* dest)
267274
{
268275
MKL_INT j;
@@ -284,6 +291,13 @@ static void vdIsnan(MKL_INT n, const double* x1, bool* dest)
284291
dest[j] = isnand(x1[j]);
285292
};
286293
};
294+
static void vdSignBit(MKL_INT n, const double* x1, bool* dest)
295+
{
296+
MKL_INT j;
297+
for (j=0; j<n; j++) {
298+
dest[j] = signbit(x1[j]);
299+
};
300+
};
287301
#endif
288302

289303
#ifdef USE_VML

numexpr/msvc_function_stubs.hpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,8 @@
4141
#define fabsf(x) ((float)fabs((double)(x)))
4242
#define fmodf(x, y) ((float)fmod((double)(x), (double)(y)))
4343
#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)))
4446
#define ceilf(x) ((float)ceil((double)(x)))
4547
#define hypotf(x) ((float)hypot((double)(x)))
4648
#define rintf(x) ((float)rint((double)(x)))
@@ -160,6 +162,10 @@ inline float nextafterf2(float x, float y) {
160162
return nextafterf(x, y);
161163
}
162164

165+
inline float copysignf2(float x, float y) {
166+
return copysignf(x, y);
167+
}
168+
163169

164170
// Boolean output functions
165171
inline bool isnanf2(float x) {
@@ -197,4 +203,8 @@ inline float truncf2(float x) {
197203
return truncf(x);
198204
}
199205

206+
inline float signbitf2(float x) {
207+
return signbitf(x);
208+
}
209+
200210
#endif // NUMEXPR_MSVC_FUNCTION_STUBS_HPP

numexpr/necompiler.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,9 @@
7777
"hypot",
7878
"round",
7979
"trunc",
80-
"nextafter"
80+
"nextafter",
81+
"copysign",
82+
"signbit"
8183
]
8284

8385

numexpr/numexpr_config.hpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,8 @@
4141
#include "mkl_service.h"
4242
#endif
4343
#include <cmath>
44-
44+
//no single precision version of signbit in C++ standard
45+
inline bool signbitf(float x) { return signbit((double)x); }
4546
#ifdef _WIN32
4647
#ifndef __MINGW32__
4748
#include "missing_posix_functions.hpp"

numexpr/tests/test_numexpr.py

Lines changed: 18 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -24,11 +24,11 @@
2424
from numpy import all as alltrue
2525
from numpy import (allclose, arange, arccos, arccosh, arcsin, arcsinh, arctan,
2626
arctan2, arctanh, array, array_equal, cdouble, ceil, conj,
27-
copy, cos, cosh, empty, exp, expm1, float64, floor, fmod,
28-
hypot, int32, int64, isinf, isnan, linspace, log, log1p,
29-
log2, log10, nextafter, ones_like, prod, ravel, rec, round,
30-
shape, sin, sinh, sqrt, sum, tan, tanh, trunc, uint16,
31-
where, zeros)
27+
copy, copysign, cos, cosh, empty, exp, expm1, float64,
28+
floor, fmod, hypot, int32, int64, isfinite, isinf, isnan,
29+
linspace, log, log1p, log2, log10, nextafter, ones_like,
30+
prod, ravel, rec, round, shape, signbit, sin, sinh, sqrt,
31+
sum, tan, tanh, trunc, uint16, where, zeros)
3232
from numpy.testing import (assert_allclose, assert_array_almost_equal,
3333
assert_array_equal, assert_equal)
3434

@@ -728,20 +728,26 @@ def test_bool_funcs(self):
728728
a = np.arange(2 * array_size, dtype=dtype)
729729
a[array_size//2] = np.nan
730730
a[array_size//3] = np.inf
731+
a[array_size//4] = -2
732+
733+
assert_equal(evaluate("isnan(a)"), isnan(a))
734+
assert_equal(evaluate("isfinite(a)"), isfinite(a))
735+
assert_equal(evaluate("isinf(a)"), isinf(a))
736+
assert_equal(evaluate("signbit(a)"), signbit(a))
731737

732-
assert np.all(evaluate("isnan(a)") == np.isnan(a))
733-
assert np.all(evaluate("isfinite(a)") == np.isfinite(a))
734-
assert np.all(evaluate("isinf(a)") == np.isinf(a))
735738
a = a.astype(np.float64)
736739
assert a.dtype == np.float64
737-
assert np.all(evaluate("isnan(a)") == np.isnan(a))
738-
assert np.all(evaluate("isfinite(a)") == np.isfinite(a))
739-
assert np.all(evaluate("isinf(a)") == np.isinf(a))
740+
assert_equal(evaluate("isnan(a)"), isnan(a))
741+
assert_equal(evaluate("isfinite(a)"), isfinite(a))
742+
assert_equal(evaluate("isinf(a)"), isinf(a))
743+
assert_equal(evaluate("signbit(a)"), signbit(a))
744+
740745
a = a.astype(np.complex128)
741746
assert a.dtype == np.complex128
742747
assert np.all(evaluate("isnan(a)") == np.isnan(a))
743748
assert np.all(evaluate("isfinite(a)") == np.isfinite(a))
744749
assert np.all(evaluate("isinf(a)") == np.isinf(a))
750+
# signbit not defined for complex numbers
745751

746752
if 'sparc' not in platform.machine():
747753
# Execution order set here so as to not use too many threads
@@ -814,7 +820,7 @@ def test_changing_nthreads_01_dec(self):
814820
tests.append(('1_ARG_FUNCS', func1tests))
815821

816822
func2tests = []
817-
for func in ['arctan2', 'fmod', 'hypot', 'nextafter']:
823+
for func in ['arctan2', 'fmod', 'hypot', 'nextafter', 'copysign']:
818824
func2tests.append("a + %s(b+c, d+1)" % func)
819825
func2tests.append("a + %s(b+c, 1)" % func)
820826
func2tests.append("a + %s(1, d+1)" % func)

0 commit comments

Comments
 (0)