Skip to content

Commit d4d1b9c

Browse files
Merge pull request #531 from pydata/add_floordiv
Added floor division and log2
2 parents 19b16cc + c9775f2 commit d4d1b9c

15 files changed

+745
-297
lines changed

ADDFUNCS.rst

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ Example:
5454
#define FUNC_FF(...)
5555
#endif
5656
...
57-
FUNC_FF(FUNC_MYFUNC_FF, "myfunc_ff", myfuncf, myfuncf2, vfMyfunc)
57+
FUNC_FF(FUNC_MYFUNC_FF, "myfunc_ff", myfuncf, myfuncf2, vsMyfunc)
5858
FUNC_FF(FUNC_FF_LAST, NULL, NULL, NULL, NULL)
5959
#ifdef ELIDE_FUNC_FF
6060
#undef ELIDE_FUNC_FF
@@ -171,7 +171,7 @@ Add clauses to generate the FUNC_CODES from the ``functions.hpp`` header, making
171171
};
172172
#endif
173173
174-
Some functions (e.g. ``fmod``, ``isnan``) are not available in MKL, and so must be hard-coded here as well:
174+
Some functions (e.g. ``fmod``, ``isnan``) are not available in MKL, and so must be hard-coded in ``bespoke_functions.hpp`` as well:
175175

176176
.. code-block:: cpp
177177
@@ -186,7 +186,7 @@ Some functions (e.g. ``fmod``, ``isnan``) are not available in MKL, and so must
186186
};
187187
#endif
188188
189-
The complex case is slightlñy different (see other examples in the same file).
189+
The complex case is slightly different (see other examples in the same file).
190190

191191
Add case handling to the ``check_program`` function
192192

doc/user_guide.rst

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -188,10 +188,10 @@ Supported operators
188188

189189
*NumExpr* supports the set of operators listed below:
190190

191-
* Bitwise operators (and, or, not, xor): :code:`&, |, ~, ^`
191+
* Bitwise and logical operators (and, or, not, xor): :code:`&, |, ~, ^`
192192
* Comparison operators: :code:`<, <=, ==, !=, >=, >`
193193
* Unary arithmetic operators: :code:`-`
194-
* Binary arithmetic operators: :code:`+, -, *, /, **, %, <<, >>`
194+
* Binary arithmetic operators: :code:`+, -, *, /, //, **, %, <<, >>`
195195

196196

197197
Supported functions
@@ -203,22 +203,33 @@ The next are the current supported set:
203203
is true, number2 otherwise.
204204
* :code:`{isinf, isnan, isfinite}(float|complex): bool` -- returns element-wise True
205205
for ``inf`` or ``NaN``, ``NaN``, not ``inf`` respectively.
206+
* :code:`signbit(float|complex): bool` -- returns element-wise True if signbit is set
207+
False otherwise.
206208
* :code:`{sin,cos,tan}(float|complex): float|complex` -- trigonometric sine,
207209
cosine or tangent.
208210
* :code:`{arcsin,arccos,arctan}(float|complex): float|complex` -- trigonometric
209211
inverse sine, cosine or tangent.
210212
* :code:`arctan2(float1, float2): float` -- trigonometric inverse tangent of
211213
float1/float2.
214+
* :code:`hypot(float1, float2): float` -- Euclidean distance between float1, float2
215+
* :code:`nextafter(float1, float2): float` -- next representable floating-point value after
216+
float1 in direction of float2
217+
* :code:`copysign(float1, float2): float` -- return number with magnitude of float1 and
218+
sign of float2
219+
* :code:`{maximum,minimum}(float1, float2): float` -- return max/min of float1, float2
212220
* :code:`{sinh,cosh,tanh}(float|complex): float|complex` -- hyperbolic sine,
213221
cosine or tangent.
214222
* :code:`{arcsinh,arccosh,arctanh}(float|complex): float|complex` -- hyperbolic
215223
inverse sine, cosine or tangent.
216-
* :code:`{log,log10,log1p}(float|complex): float|complex` -- natural, base-10 and
224+
* :code:`{log,log10,log1p,log2}(float|complex): float|complex` -- natural, base-10 and
217225
log(1+x) logarithms.
218226
* :code:`{exp,expm1}(float|complex): float|complex` -- exponential and exponential
219227
minus one.
220228
* :code:`sqrt(float|complex): float|complex` -- square root.
221-
* :code:`abs(float|complex): float|complex` -- absolute value.
229+
* :code:`trunc(float): float` -- round towards zero
230+
* :code:`round(float|complex|int): float|complex|int` -- round to nearest integer (`rint`)
231+
* :code:`sign(float|complex|int): float|complex|int` -- return -1, 0, +1 depending on sign
232+
* :code:`abs(float|complex|int): float|complex|int` -- absolute value.
222233
* :code:`conj(complex): complex` -- conjugate value.
223234
* :code:`{real,imag}(complex): float` -- real or imaginary part of complex.
224235
* :code:`complex(float, float): complex` -- complex from real and imaginary

numexpr/bespoke_functions.hpp

Lines changed: 292 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,292 @@
1+
#include <numpy/npy_cpu.h>
2+
#include <math.h>
3+
#include <string.h>
4+
#include <assert.h>
5+
#include <vector>
6+
#include "numexpr_config.hpp" // isnan definitions
7+
8+
// Generic sign function
9+
inline int signi(int x) {return (0 < x) - (x < 0);}
10+
inline long signl(long x) {return (0 < x) - (x < 0);}
11+
inline double sign(double x){
12+
// Floats: -1.0, 0.0, +1.0, NaN stays NaN
13+
if (isnand(x)) {return NAN;}
14+
if (x > 0) {return 1;}
15+
if (x < 0) {return -1;}
16+
return 0; // handles +0.0 and -0.0
17+
}
18+
inline float signf(float x){
19+
// Floats: -1.0, 0.0, +1.0, NaN stays NaN
20+
if (isnanf_(x)) {return NAN;}
21+
if (x > 0) {return 1;}
22+
if (x < 0) {return -1;}
23+
return 0; // handles +0.0 and -0.0
24+
}
25+
26+
// round function for ints
27+
inline int rinti(int x) {return x;}
28+
inline long rintl(long x) {return x;}
29+
// abs function for ints
30+
inline int fabsi(int x) {return x<0 ? -x: x;}
31+
inline long fabsl(long x) {return x<0 ? -x: x;}
32+
// fmod function for ints
33+
inline int fmodi(int x, int y) {return (int)fmodf((float)x, (float)y);}
34+
inline long fmodl(long x, long y) {return (long)fmodf((long)x, (long)y);}
35+
36+
#ifdef USE_VML
37+
static void viRint(MKL_INT n, const int* x, int* dest)
38+
{
39+
memcpy(dest, x, n * sizeof(int)); // just copy x1 which is already int
40+
};
41+
42+
static void vlRint(MKL_INT n, const long* x, long* dest)
43+
{
44+
memcpy(dest, x, n * sizeof(long)); // just copy x1 which is already int
45+
};
46+
47+
static void viFabs(MKL_INT n, const int* x, int* dest)
48+
{
49+
MKL_INT j;
50+
for (j=0; j<n; j++) {
51+
dest[j] = x[j] < 0 ? -x[j]: x[j];
52+
};
53+
};
54+
55+
static void vlFabs(MKL_INT n, const long* x, long* dest)
56+
{
57+
MKL_INT j;
58+
for (j=0; j<n; j++) {
59+
dest[j] = x[j] < 0 ? -x[j]: x[j];
60+
};
61+
};
62+
63+
/* Fake vsConj function just for casting purposes inside numexpr */
64+
static void vsConj(MKL_INT n, const float* x1, float* dest)
65+
{
66+
MKL_INT j;
67+
for (j=0; j<n; j++) {
68+
dest[j] = x1[j];
69+
};
70+
};
71+
72+
/* fmod not available in VML */
73+
static void vsfmod(MKL_INT n, const float* x1, const float* x2, float* dest)
74+
{
75+
MKL_INT j;
76+
for(j=0; j < n; j++) {
77+
dest[j] = fmodf(x1[j], x2[j]);
78+
};
79+
}
80+
static void vdfmod(MKL_INT n, const double* x1, const double* x2, double* dest)
81+
{
82+
MKL_INT j;
83+
for(j=0; j < n; j++) {
84+
dest[j] = fmod(x1[j], x2[j]);
85+
};
86+
};
87+
static void vifmod(MKL_INT n, const int* x1, const int* x2, int* dest)
88+
{
89+
MKL_INT j;
90+
for(j=0; j < n; j++) {
91+
dest[j] = fmodi(x1[j], x2[j]);
92+
};
93+
};
94+
static void vlfmod(MKL_INT n, const long* x1, const long* x2, long* dest)
95+
{
96+
MKL_INT j;
97+
for(j=0; j < n; j++) {
98+
dest[j] = fmodl(x1[j], x2[j]);
99+
};
100+
};
101+
102+
/* no isnan, isfinite, isinf or signbit in VML */
103+
static void vsIsfinite(MKL_INT n, const float* x1, bool* dest)
104+
{
105+
MKL_INT j;
106+
for (j=0; j<n; j++) {
107+
dest[j] = isfinitef_(x1[j]);
108+
};
109+
};
110+
static void vsIsinf(MKL_INT n, const float* x1, bool* dest)
111+
{
112+
MKL_INT j;
113+
for (j=0; j<n; j++) {
114+
dest[j] = isinff_(x1[j]);
115+
};
116+
};
117+
static void vsIsnan(MKL_INT n, const float* x1, bool* dest)
118+
{
119+
MKL_INT j;
120+
for (j=0; j<n; j++) {
121+
dest[j] = isnanf_(x1[j]);
122+
};
123+
};
124+
static void vsSignBit(MKL_INT n, const float* x1, bool* dest)
125+
{
126+
MKL_INT j;
127+
for (j=0; j<n; j++) {
128+
dest[j] = signbitf(x1[j]);
129+
};
130+
};
131+
132+
/* no isnan, isfinite, isinf, signbit in VML */
133+
static void vdIsfinite(MKL_INT n, const double* x1, bool* dest)
134+
{
135+
MKL_INT j;
136+
for (j=0; j<n; j++) {
137+
dest[j] = isfinited(x1[j]);
138+
};
139+
};
140+
static void vdIsinf(MKL_INT n, const double* x1, bool* dest)
141+
{
142+
MKL_INT j;
143+
for (j=0; j<n; j++) {
144+
dest[j] = isinfd(x1[j]);
145+
};
146+
};
147+
static void vdIsnan(MKL_INT n, const double* x1, bool* dest)
148+
{
149+
MKL_INT j;
150+
for (j=0; j<n; j++) {
151+
dest[j] = isnand(x1[j]);
152+
};
153+
};
154+
static void vdSignBit(MKL_INT n, const double* x1, bool* dest)
155+
{
156+
MKL_INT j;
157+
for (j=0; j<n; j++) {
158+
dest[j] = signbit(x1[j]);
159+
};
160+
};
161+
162+
/* no isnan, isfinite or isinf in VML */
163+
static void vzIsfinite(MKL_INT n, const MKL_Complex16* x1, bool* dest)
164+
{
165+
MKL_INT j;
166+
for (j=0; j<n; j++) {
167+
dest[j] = isfinited(x1[j].real) && isfinited(x1[j].imag);
168+
};
169+
};
170+
static void vzIsinf(MKL_INT n, const MKL_Complex16* x1, bool* dest)
171+
{
172+
MKL_INT j;
173+
for (j=0; j<n; j++) {
174+
dest[j] = isinfd(x1[j].real) || isinfd(x1[j].imag);
175+
};
176+
};
177+
static void vzIsnan(MKL_INT n, const MKL_Complex16* x1, bool* dest)
178+
{
179+
MKL_INT j;
180+
for (j=0; j<n; j++) {
181+
dest[j] = isnand(x1[j].real) || isnand(x1[j].imag);
182+
};
183+
};
184+
185+
/* Fake vdConj function just for casting purposes inside numexpr */
186+
static void vdConj(MKL_INT n, const double* x1, double* dest)
187+
{
188+
MKL_INT j;
189+
for (j=0; j<n; j++) {
190+
dest[j] = x1[j];
191+
};
192+
};
193+
194+
/* various functions not available in VML */
195+
static void vzExpm1(MKL_INT n, const MKL_Complex16* x1, MKL_Complex16* dest)
196+
{
197+
MKL_INT j;
198+
vzExp(n, x1, dest);
199+
for (j=0; j<n; j++) {
200+
dest[j].real -= 1.0;
201+
};
202+
};
203+
204+
static void vzLog1p(MKL_INT n, const MKL_Complex16* x1, MKL_Complex16* dest)
205+
{
206+
MKL_INT j;
207+
for (j=0; j<n; j++) {
208+
dest[j].real = x1[j].real + 1;
209+
dest[j].imag = x1[j].imag;
210+
};
211+
vzLn(n, dest, dest);
212+
};
213+
214+
static void vzLog2(MKL_INT n, const MKL_Complex16* x1, MKL_Complex16* dest)
215+
{
216+
MKL_INT j;
217+
vzLn(n, x1, dest);
218+
for (j=0; j<n; j++) {
219+
dest[j].real = dest[j].real * M_LOG2_E;
220+
dest[j].imag = dest[j].imag * M_LOG2_E;
221+
};
222+
};
223+
224+
static void vzRint(MKL_INT n, const MKL_Complex16* x1, MKL_Complex16* dest)
225+
{
226+
MKL_INT j;
227+
for (j=0; j<n; j++) {
228+
dest[j].real = rint(x1[j].real);
229+
dest[j].imag = rint(x1[j].imag);
230+
};
231+
};
232+
233+
/* Use this instead of native vzAbs in VML as it seems to work badly */
234+
static void vzAbs_(MKL_INT n, const MKL_Complex16* x1, MKL_Complex16* dest)
235+
{
236+
MKL_INT j;
237+
for (j=0; j<n; j++) {
238+
dest[j].real = sqrt(x1[j].real*x1[j].real + x1[j].imag*x1[j].imag);
239+
dest[j].imag = 0;
240+
};
241+
};
242+
243+
/*sign functions*/
244+
static void vsSign(MKL_INT n, const float* x1, float* dest)
245+
{
246+
MKL_INT j;
247+
for(j=0; j < n; j++) {
248+
dest[j] = signf(x1[j]);
249+
};
250+
};
251+
static void vdSign(MKL_INT n, const double* x1, double* dest)
252+
{
253+
MKL_INT j;
254+
for(j=0; j < n; j++) {
255+
dest[j] = sign(x1[j]);
256+
};
257+
};
258+
static void viSign(MKL_INT n, const int* x1, int* dest)
259+
{
260+
MKL_INT j;
261+
for(j=0; j < n; j++) {
262+
dest[j] = signi(x1[j]);
263+
};
264+
};
265+
static void vlSign(MKL_INT n, const long* x1, long* dest)
266+
{
267+
MKL_INT j;
268+
for(j=0; j < n; j++) {
269+
dest[j] = signl(x1[j]);
270+
};
271+
};
272+
static void vzSign(MKL_INT n, const MKL_Complex16* x1, MKL_Complex16* dest)
273+
{
274+
MKL_INT j;
275+
double mag;
276+
for(j=0; j < n; j++) {
277+
mag = sqrt(x1[j].real*x1[j].real + x1[j].imag*x1[j].imag);
278+
if (isnand(mag)) {
279+
dest[j].real = NAN;
280+
dest[j].imag = NAN;
281+
}
282+
else if (mag == 0) {
283+
dest[j].real = 0;
284+
dest[j].imag = 0;
285+
}
286+
else {
287+
dest[j].real = x1[j].real / mag;
288+
dest[j].imag = x1[j].imag / mag;
289+
}
290+
};
291+
};
292+
#endif

0 commit comments

Comments
 (0)