/* -*- c -*- */ /* ***************************************************************************** ** INCLUDES ** ***************************************************************************** */ #include "Python.h" #include "numpy/noprefix.h" #define _UMATHMODULE #include "numpy/ufuncobject.h" #include "abstract.h" #include "config.h" #include /* ***************************************************************************** ** BASIC MATH FUNCTIONS ** ***************************************************************************** */ /* A whole slew of basic math functions are provided originally by Konrad Hinsen. */ #if !defined(__STDC__) && !defined(_MSC_VER) extern double fmod (double, double); extern double frexp (double, int *); extern double ldexp (double, int); extern double modf (double, double *); #endif #ifndef M_PI #define M_PI 3.14159265358979323846264338328 #endif #if defined(DISTUTILS_USE_SDK) /* win32 on AMD64 build architecture */ /* See also http://projects.scipy.org/scipy/numpy/ticket/164 */ #ifndef HAVE_FABSF #ifdef fabsf #undef fabsf #endif static float fabsf(float x) { return (float)fabs((double)(x)); } #endif #ifndef HAVE_HYPOTF static float hypotf(float x, float y) { return (float)hypot((double)(x), (double)(y)); } #endif #ifndef HAVE_RINTF #ifndef HAVE_RINT static double rint (double x); #endif static float rintf(float x) { return (float)rint((double)(x)); } #endif #ifndef HAVE_FREXPF static float frexpf(float x, int * i) { return (float)frexp((double)(x), i); } #endif #ifndef HAVE_LDEXPF static float ldexpf(float x, int i) { return (float)ldexp((double)(x), i); } #endif #define tanhf nc_tanhf #endif #ifndef HAVE_INVERSE_HYPERBOLIC static double acosh(double x) { return 2*log(sqrt((x+1.0)/2)+sqrt((x-1.0)/2)); } double log1p(double); static double asinh(double xx) { double x, d; int sign; if (xx < 0.0) { sign = -1; x = -xx; } else { sign = 1; x = xx; } if (x > 1e8) { d = x; } else { d = sqrt(x*x + 1); } return sign*log1p(x*(1.0 + x/(d+1))); } static double atanh(double x) { return 0.5*log1p(2.0*x/(1.0-x)); } #endif #if !defined(HAVE_INVERSE_HYPERBOLIC_FLOAT) #ifdef HAVE_FLOAT_FUNCS #ifdef log1pf #undef log1pf #endif #ifdef logf #undef logf #endif #ifdef sqrtf #undef sqrtf #endif float log1pf(float); #ifdef DISTUTILS_USE_SDK DL_IMPORT(float) logf(float); DL_IMPORT(float) sqrtf(float); #else /* should these be extern?: */ float logf(float); float sqrtf(float); #endif #ifdef acoshf #undef acoshf #endif static float acoshf(float x) { return 2*logf(sqrtf((x+1)/2)+sqrtf((x-1)/2)); } #ifdef asinhf #undef asinhf #endif static float asinhf(float xx) { float x, d; int sign; if (xx < 0) { sign = -1; x = -xx; } else { sign = 1; x = xx; } if (x > 1e5) { d = x; } else { d = sqrtf(x*x + 1); } return sign*log1pf(x*(1 + x/(d+1))); } #ifdef atanhf #undef atanhf #endif static float atanhf(float x) { return log1pf(2*x/(1-x))/2; } #else #ifdef acoshf #undef acoshf #endif static float acoshf(float x) { return (float)acosh((double)(x)); } #ifdef asinhf #undef asinhf #endif static float asinhf(float x) { return (float)asinh((double)(x)); } #ifdef atanhf #undef atanhf #endif static float atanhf(float x) { return (float)atanh((double)(x)); } #endif #endif #if !defined(HAVE_INVERSE_HYPERBOLIC_LONGDOUBLE) #ifdef HAVE_LONGDOUBLE_FUNCS #ifdef logl #undef logl #endif #ifdef sqrtl #undef sqrtl #endif #ifdef log1pl #undef log1pl #endif longdouble logl(longdouble); longdouble sqrtl(longdouble); longdouble log1pl(longdouble); #ifdef acoshl #undef acoshl #endif static longdouble acoshl(longdouble x) { return 2*logl(sqrtl((x+1.0)/2)+sqrtl((x-1.0)/2)); } #ifdef asinhl #undef asinhl #endif static longdouble asinhl(longdouble xx) { longdouble x, d; int sign; if (xx < 0.0) { sign = -1; x = -xx; } else { sign = 1; x = xx; } if (x > 1e17) { d = x; } else { d = sqrtl(x*x + 1); } return sign*log1pl(x*(1.0 + x/(d+1))); } #ifdef atanhl #undef atanhl #endif static longdouble atanhl(longdouble x) { return 0.5*log1pl(2.0*x/(1.0-x)); } #else #ifdef acoshl #undef acoshl #endif static longdouble acoshl(longdouble x) { return (longdouble)acosh((double)(x)); } #ifdef asinhl #undef asinhl #endif static longdouble asinhl(longdouble x) { return (longdouble)asinh((double)(x)); } #ifdef atanhl #undef atanhl #endif static longdouble atanhl(longdouble x) { return (longdouble)atanh((double)(x)); } #endif #endif #ifdef HAVE_HYPOT #if !defined(NeXT) && !defined(_MSC_VER) extern double hypot(double, double); #endif #else static double hypot(double x, double y) { double yx; x = fabs(x); y = fabs(y); if (x < y) { double temp = x; x = y; y = temp; } if (x == 0.) return 0.; else { yx = y/x; return x*sqrt(1.+yx*yx); } } #endif #ifndef HAVE_RINT static double rint (double x) { double y, r; y = floor(x); r = x - y; if (r > 0.5) goto rndup; /* Round to nearest even */ if (r==0.5) { r = y - 2.0*floor(0.5*y); if (r==1.0) { rndup: y+=1.0; } } return y; } #endif /* Define isnan, isinf, isfinite, signbit if needed */ /* Use fpclassify if possible */ /* isnan, isinf -- these will use macros and then fpclassify if available before defaulting to a dumb convert-to-double version... isfinite -- define a macro if not already available signbit -- if macro available use it, otherwise define a function and a dumb convert-to-double version for other types. */ #if defined(fpclassify) #if !defined(isnan) #define isnan(x) (fpclassify(x) == FP_NAN) #endif #if !defined(isinf) #define isinf(x) (fpclassify(x) == FP_INFINITE) #endif #else /* check to see if already have a function like this */ #if !defined(HAVE_ISNAN) #if !defined(isnan) #include "_isnan.c" #endif #endif /* HAVE_ISNAN */ #if !defined(HAVE_ISINF) #if !defined(isinf) #define isinf(x) (!isnan((x)) && isnan((x)-(x))) #endif #endif /* HAVE_ISINF */ #endif /* defined(fpclassify) */ /* Define signbit if needed */ #if !defined(signbit) #include "_signbit.c" #endif /* Now defined the extended type macros */ #if !defined(isnan) #if !defined(HAVE_LONGDOUBLE_FUNCS) || !defined(HAVE_ISNAN) #define isnanl(x) isnan((double)(x)) #endif #if !defined(HAVE_FLOAT_FUNCS) || !defined(HAVE_ISNAN) #define isnanf(x) isnan((double)(x)) #endif #else /* !defined(isnan) */ #define isnanl(x) isnan((x)) #define isnanf(x) isnan((x)) #endif /* !defined(isnan) */ #if !defined(isinf) #if !defined(HAVE_LONGDOUBLE_FUNCS) || !defined(HAVE_ISINF) #define isinfl(x) (!isnanl((x)) && isnanl((x)-(x))) #endif #if !defined(HAVE_FLOAT_FUNCS) || !defined(HAVE_ISINF) #define isinff(x) (!isnanf((x)) && isnanf((x)-(x))) #endif #else /* !defined(isinf) */ #define isinfl(x) isinf((x)) #define isinff(x) isinf((x)) #endif /* !defined(isinf) */ #if !defined(signbit) #define signbitl(x) ((longdouble) signbit((double)(x))) #define signbitf(x) ((float) signbit((double) (x))) #else #define signbitl(x) signbit((x)) #define signbitf(x) signbit((x)) #endif #if !defined(isfinite) #define isfinite(x) (!(isinf((x)) || isnan((x)))) #endif #define isfinitef(x) (!(isinff((x)) || isnanf((x)))) #define isfinitel(x) (!(isinfl((x)) || isnanl((x)))) float degreesf(float x) { return x * (float)(180.0/M_PI); } double degrees(double x) { return x * (180.0/M_PI); } longdouble degreesl(longdouble x) { return x * (180.0L/M_PI); } float radiansf(float x) { return x * (float)(M_PI/180.0); } double radians(double x) { return x * (M_PI/180.0); } longdouble radiansl(longdouble x) { return x * (M_PI/180.0L); } /* First, the C functions that do the real work */ /* if C99 extensions not available then define dummy functions that use the double versions for sin, cos, tan sinh, cosh, tanh, fabs, floor, ceil, fmod, sqrt, log10, log, exp, fabs asin, acos, atan, asinh, acosh, atanh hypot, atan2, pow */ /**begin repeat #kind=(sin,cos,tan,sinh,cosh,tanh,fabs,floor,ceil,sqrt,log10,log,exp,asin,acos,atan,rint)*2# #typ=longdouble*17, float*17# #c=l*17,f*17# #TYPE=LONGDOUBLE*17, FLOAT*17# */ #ifndef HAVE_@TYPE@_FUNCS #ifdef @kind@@c@ #undef @kind@@c@ #endif @typ@ @kind@@c@(@typ@ x) { return (@typ@) @kind@((double)x); } #endif /**end repeat**/ /**begin repeat #kind=(atan2,hypot,pow,fmod)*2# #typ=longdouble*4, float*4# #c=l*4,f*4# #TYPE=LONGDOUBLE*4,FLOAT*4# */ #ifndef HAVE_@TYPE@_FUNCS #ifdef @kind@@c@ #undef @kind@@c@ #endif @typ@ @kind@@c@(@typ@ x, @typ@ y) { return (@typ@) @kind@((double)x, (double) y); } #endif /**end repeat**/ /**begin repeat #kind=modf*2# #typ=longdouble, float# #c=l,f# #TYPE=LONGDOUBLE, FLOAT# */ #ifndef HAVE_@TYPE@_FUNCS #ifdef modf@c@ #undef modf@c@ #endif @typ@ modf@c@(@typ@ x, @typ@ *iptr) { double nx, niptr, y; nx = (double) x; y = modf(nx, &niptr); *iptr = (@typ@) niptr; return (@typ@) y; } #endif /**end repeat**/ #ifndef HAVE_LOG1P double log1p(double x) { double u = 1. + x; if (u == 1.0) { return x; } else { return log(u) * x / (u-1.); } } #endif #if !defined(HAVE_LOG1P) || !defined(HAVE_LONGDOUBLE_FUNCS) #ifdef log1pl #undef log1pl #endif longdouble log1pl(longdouble x) { longdouble u = 1. + x; if (u == 1.0) { return x; } else { return logl(u) * x / (u-1.); } } #endif #if !defined(HAVE_LOG1P) || !defined(HAVE_FLOAT_FUNCS) #ifdef log1pf #undef log1pf #endif float log1pf(float x) { float u = 1 + x; if (u == 1) { return x; } else { return logf(u) * x / (u-1); } } #endif #ifndef HAVE_EXPM1 static double expm1(double x) { double u = exp(x); if (u == 1.0) { return x; } else if (u-1.0 == -1.0) { return -1; } else { return (u-1.0) * x/log(u); } } #endif #if !defined(HAVE_EXPM1) || !defined(HAVE_LONGDOUBLE_FUNCS) #ifdef expml1 #undef expml1 #endif static longdouble expm1l(longdouble x) { longdouble u = expl(x); if (u == 1.0) { return x; } else if (u-1.0 == -1.0) { return -1; } else { return (u-1.0) * x/logl(u); } } #endif #if !defined(HAVE_EXPM1) || !defined(HAVE_FLOAT_FUNCS) #ifdef expm1f #undef expm1f #endif static float expm1f(float x) { float u = expf(x); if (u == 1) { return x; } else if (u-1 == -1) { return -1; } else { return (u-1) * x/logf(u); } } #endif /* ***************************************************************************** ** COMPLEX FUNCTIONS ** ***************************************************************************** */ /* Don't pass structures between functions (only pointers) because how structures are passed is compiler dependent and could cause segfaults if ufuncobject.c is compiled with a different compiler than an extension that makes use of the UFUNC API */ /**begin repeat #typ=float, double, longdouble# #c=f,,l# */ /* constants */ static c@typ@ nc_1@c@ = {1., 0.}; static c@typ@ nc_half@c@ = {0.5, 0.}; static c@typ@ nc_i@c@ = {0., 1.}; static c@typ@ nc_i2@c@ = {0., 0.5}; /* static c@typ@ nc_mi@c@ = {0., -1.}; static c@typ@ nc_pi2@c@ = {M_PI/2., 0.}; */ static void nc_sum@c@(c@typ@ *a, c@typ@ *b, c@typ@ *r) { r->real = a->real + b->real; r->imag = a->imag + b->imag; return; } static void nc_diff@c@(c@typ@ *a, c@typ@ *b, c@typ@ *r) { r->real = a->real - b->real; r->imag = a->imag - b->imag; return; } static void nc_neg@c@(c@typ@ *a, c@typ@ *r) { r->real = -a->real; r->imag = -a->imag; return; } static void nc_prod@c@(c@typ@ *a, c@typ@ *b, c@typ@ *r) { register @typ@ ar=a->real, br=b->real, ai=a->imag, bi=b->imag; r->real = ar*br - ai*bi; r->imag = ar*bi + ai*br; return; } static void nc_quot@c@(c@typ@ *a, c@typ@ *b, c@typ@ *r) { register @typ@ ar=a->real, br=b->real, ai=a->imag, bi=b->imag; register @typ@ d = br*br + bi*bi; r->real = (ar*br + ai*bi)/d; r->imag = (ai*br - ar*bi)/d; return; } static void nc_sqrt@c@(c@typ@ *x, c@typ@ *r) { @typ@ s,d; if (x->real == 0. && x->imag == 0.) *r = *x; else { s = sqrt@c@((fabs@c@(x->real) + hypot@c@(x->real,x->imag))/2); d = x->imag/(2*s); if (x->real > 0) { r->real = s; r->imag = d; } else if (x->imag >= 0) { r->real = d; r->imag = s; } else { r->real = -d; r->imag = -s; } } return; } static void nc_rint@c@(c@typ@ *x, c@typ@ *r) { r->real = rint@c@(x->real); r->imag = rint@c@(x->imag); } static void nc_log@c@(c@typ@ *x, c@typ@ *r) { @typ@ l = hypot@c@(x->real,x->imag); r->imag = atan2@c@(x->imag, x->real); r->real = log@c@(l); return; } static void nc_log1p@c@(c@typ@ *x, c@typ@ *r) { @typ@ l = hypot@c@(x->real + 1,x->imag); r->imag = atan2@c@(x->imag, x->real + 1); r->real = log@c@(l); return; } static void nc_exp@c@(c@typ@ *x, c@typ@ *r) { @typ@ a = exp@c@(x->real); r->real = a*cos@c@(x->imag); r->imag = a*sin@c@(x->imag); return; } static void nc_expm1@c@(c@typ@ *x, c@typ@ *r) { @typ@ a = exp@c@(x->real); r->real = a*cos@c@(x->imag) - 1; r->imag = a*sin@c@(x->imag); return; } static void nc_pow@c@(c@typ@ *a, c@typ@ *b, c@typ@ *r) { intp n; @typ@ ar=a->real, br=b->real, ai=a->imag, bi=b->imag; if (br == 0. && bi == 0.) { r->real = 1.; r->imag = 0.; return; } if (ar == 0. && ai == 0.) { r->real = 0.; r->imag = 0.; return; } if (bi == 0 && (n=(intp)br) == br) { if (n > -100 && n < 100) { c@typ@ p, aa; intp mask = 1; if (n < 0) n = -n; aa = nc_1@c@; p.real = ar; p.imag = ai; while (1) { if (n & mask) nc_prod@c@(&aa,&p,&aa); mask <<= 1; if (n < mask || mask <= 0) break; nc_prod@c@(&p,&p,&p); } r->real = aa.real; r->imag = aa.imag; if (br < 0) nc_quot@c@(&nc_1@c@, r, r); return; } } /* complexobect.c uses an inline version of this formula investigate whether this had better performance or accuracy */ nc_log@c@(a, r); nc_prod@c@(r, b, r); nc_exp@c@(r, r); return; } static void nc_prodi@c@(c@typ@ *x, c@typ@ *r) { @typ@ xr = x->real; r->real = -x->imag; r->imag = xr; return; } static void nc_acos@c@(c@typ@ *x, c@typ@ *r) { nc_prod@c@(x,x,r); nc_diff@c@(&nc_1@c@, r, r); nc_sqrt@c@(r, r); nc_prodi@c@(r, r); nc_sum@c@(x, r, r); nc_log@c@(r, r); nc_prodi@c@(r, r); nc_neg@c@(r, r); return; /* return nc_neg(nc_prodi(nc_log(nc_sum(x,nc_prod(nc_i, nc_sqrt(nc_diff(nc_1,nc_prod(x,x)))))))); */ } static void nc_acosh@c@(c@typ@ *x, c@typ@ *r) { c@typ@ t; nc_sum@c@(x, &nc_1@c@, &t); nc_diff@c@(x, &nc_1@c@, r); nc_prod@c@(&t, r, r); nc_sqrt@c@(r, r); nc_sum@c@(x, r, r); nc_log@c@(r, r); return; /* return nc_log(nc_sum(x, nc_sqrt(nc_prod(nc_sum(x,nc_1), nc_diff(x,nc_1))))); */ } static void nc_asin@c@(c@typ@ *x, c@typ@ *r) { c@typ@ a, *pa=&a; nc_prod@c@(x, x, r); nc_diff@c@(&nc_1@c@, r, r); nc_sqrt@c@(r, r); nc_prodi@c@(x, pa); nc_sum@c@(pa, r, r); nc_log@c@(r, r); nc_prodi@c@(r, r); nc_neg@c@(r, r); return; /* return nc_neg(nc_prodi(nc_log(nc_sum(nc_prod(nc_i,x), nc_sqrt(nc_diff(nc_1,nc_prod(x,x))))))); */ } static void nc_asinh@c@(c@typ@ *x, c@typ@ *r) { nc_prod@c@(x, x, r); nc_sum@c@(&nc_1@c@, r, r); nc_sqrt@c@(r, r); nc_diff@c@(r, x, r); nc_log@c@(r, r); nc_neg@c@(r, r); return; /* return nc_neg(nc_log(nc_diff(nc_sqrt(nc_sum(nc_1,nc_prod(x,x))),x))); */ } static void nc_atan@c@(c@typ@ *x, c@typ@ *r) { c@typ@ a, *pa=&a; nc_diff@c@(&nc_i@c@, x, pa); nc_sum@c@(&nc_i@c@, x, r); nc_quot@c@(r, pa, r); nc_log@c@(r,r); nc_prod@c@(&nc_i2@c@, r, r); return; /* return nc_prod(nc_i2,nc_log(nc_quot(nc_sum(nc_i,x),nc_diff(nc_i,x)))); */ } static void nc_atanh@c@(c@typ@ *x, c@typ@ *r) { c@typ@ a, *pa=&a; nc_diff@c@(&nc_1@c@, x, r); nc_sum@c@(&nc_1@c@, x, pa); nc_quot@c@(pa, r, r); nc_log@c@(r, r); nc_prod@c@(&nc_half@c@, r, r); return; /* return nc_prod(nc_half,nc_log(nc_quot(nc_sum(nc_1,x),nc_diff(nc_1,x)))); */ } static void nc_cos@c@(c@typ@ *x, c@typ@ *r) { @typ@ xr=x->real, xi=x->imag; r->real = cos@c@(xr)*cosh@c@(xi); r->imag = -sin@c@(xr)*sinh@c@(xi); return; } static void nc_cosh@c@(c@typ@ *x, c@typ@ *r) { @typ@ xr=x->real, xi=x->imag; r->real = cos@c@(xi)*cosh@c@(xr); r->imag = sin@c@(xi)*sinh@c@(xr); return; } #define M_LOG10_E 0.434294481903251827651128918916605082294397 static void nc_log10@c@(c@typ@ *x, c@typ@ *r) { nc_log@c@(x, r); r->real *= (@typ@) M_LOG10_E; r->imag *= (@typ@) M_LOG10_E; return; } static void nc_sin@c@(c@typ@ *x, c@typ@ *r) { @typ@ xr=x->real, xi=x->imag; r->real = sin@c@(xr)*cosh@c@(xi); r->imag = cos@c@(xr)*sinh@c@(xi); return; } static void nc_sinh@c@(c@typ@ *x, c@typ@ *r) { @typ@ xr=x->real, xi=x->imag; r->real = cos@c@(xi)*sinh@c@(xr); r->imag = sin@c@(xi)*cosh@c@(xr); return; } static void nc_tan@c@(c@typ@ *x, c@typ@ *r) { @typ@ sr,cr,shi,chi; @typ@ rs,is,rc,ic; @typ@ d; @typ@ xr=x->real, xi=x->imag; sr = sin@c@(xr); cr = cos@c@(xr); shi = sinh@c@(xi); chi = cosh@c@(xi); rs = sr*chi; is = cr*shi; rc = cr*chi; ic = -sr*shi; d = rc*rc + ic*ic; r->real = (rs*rc+is*ic)/d; r->imag = (is*rc-rs*ic)/d; return; } static void nc_tanh@c@(c@typ@ *x, c@typ@ *r) { @typ@ si,ci,shr,chr; @typ@ rs,is,rc,ic; @typ@ d; @typ@ xr=x->real, xi=x->imag; si = sin@c@(xi); ci = cos@c@(xi); shr = sinh@c@(xr); chr = cosh@c@(xr); rs = ci*shr; is = si*chr; rc = ci*chr; ic = si*shr; d = rc*rc + ic*ic; r->real = (rs*rc+is*ic)/d; r->imag = (is*rc-rs*ic)/d; return; } /**end repeat**/ /* ***************************************************************************** ** UFUNC LOOPS ** ***************************************************************************** */ /**begin repeat #TYPE=(BOOL, BYTE,UBYTE,SHORT,USHORT,INT,UINT,LONG,ULONG,LONGLONG,ULONGLONG,FLOAT,DOUBLE,LONGDOUBLE)*2# #OP=||, +*13, ^, -*13# #kind=add*14, subtract*14# #typ=(Bool, byte, ubyte, short, ushort, int, uint, long, ulong, longlong, ulonglong, float, double, longdouble)*2# */ static void @TYPE@_@kind@(char **args, intp *dimensions, intp *steps, void *func) { register intp i; intp is1=steps[0],is2=steps[1],os=steps[2], n=dimensions[0]; char *i1=args[0], *i2=args[1], *op=args[2]; for(i=0; ireal, \ ai=((c@typ@ *)i1)->imag, \ br=((c@typ@ *)i2)->real, \ bi=((c@typ@ *)i2)->imag; ((c@typ@ *)op)->real = ar*br - ai*bi; ((c@typ@ *)op)->imag = ar*bi + ai*br; } } static void @TYP@_divide(char **args, intp *dimensions, intp *steps, void *func) { register intp i; intp is1=steps[0], is2=steps[1], os=steps[2], n=dimensions[0]; char *i1=args[0], *i2=args[1], *op=args[2]; for (i=0; ireal, \ ai=((c@typ@ *)i1)->imag, \ br=((c@typ@ *)i2)->real, \ bi=((c@typ@ *)i2)->imag; register @typ@ d = br*br + bi*bi; ((c@typ@ *)op)->real = (ar*br + ai*bi)/d; ((c@typ@ *)op)->imag = (ai*br - ar*bi)/d; } } static void @TYP@_floor_divide(char **args, intp *dimensions, intp *steps, void *func) { register intp i; intp is1=steps[0],is2=steps[1],os=steps[2],n=dimensions[0]; char *i1=args[0], *i2=args[1], *op=args[2]; for(i=0; ireal, \ ai=((c@typ@ *)i1)->imag, \ br=((c@typ@ *)i2)->real, \ bi=((c@typ@ *)i2)->imag; register @typ@ d = br*br + bi*bi; ((c@typ@ *)op)->real = floor@c@((ar*br + ai*bi)/d); ((c@typ@ *)op)->imag = 0; } } #define @TYP@_true_divide @TYP@_divide /**end repeat**/ /**begin repeat #TYP=UBYTE,USHORT,UINT,ULONG,ULONGLONG# #typ=ubyte, ushort, uint, ulong, ulonglong# */ static void @TYP@_divide(char **args, intp *dimensions, intp *steps, void *func) { register intp i, is1=steps[0],is2=steps[1],os=steps[2],n=dimensions[0]; char *i1=args[0], *i2=args[1], *op=args[2]; for(i=0; i 0) != (y > 0)) && (x % y != 0)) tmp--; *((@typ@ *)op)= tmp; } } } /**end repeat**/ /**begin repeat #TYP=BYTE,UBYTE,SHORT,USHORT,INT,UINT,LONG,ULONG,LONGLONG,ULONGLONG# #typ=char, ubyte, short, ushort, int, uint, long, ulong, longlong, ulonglong# #otyp=float*4, double*6# */ static void @TYP@_true_divide(char **args, intp *dimensions, intp *steps, void *func) { register intp i, is1=steps[0],is2=steps[1],os=steps[2],n=dimensions[0]; char *i1=args[0], *i2=args[1], *op=args[2]; for(i=0; ireal; xi = x->imag; y->real = xr*xr - xi*xi; y->imag = 2*xr*xi; } } /**end repeat**/ static PyObject * Py_square(PyObject *o) { return PyNumber_Multiply(o, o); } /**begin repeat #TYP=BYTE,UBYTE,SHORT,USHORT,INT,UINT,LONG,ULONG,LONGLONG,ULONGLONG,FLOAT,DOUBLE,LONGDOUBLE# #typ=char, ubyte, short, ushort, int, uint, long, ulong, longlong, ulonglong, float, double, longdouble# */ static void @TYP@_reciprocal(char **args, intp *dimensions, intp *steps, void *data) { intp i, is1 = steps[0], os = steps[1], n = dimensions[0]; char *i1 = args[0], *op = args[1]; for (i = 0; i < n; i++, i1 += is1, op += os) { @typ@ x = *((@typ@ *)i1); *((@typ@ *)op) = (@typ@) (1.0 / x); } } /**end repeat**/ /**begin repeat #TYP=CFLOAT,CDOUBLE,CLONGDOUBLE# #typ=float, double, longdouble# */ static void @TYP@_reciprocal(char **args, intp *dimensions, intp *steps, void *data) { intp i, is1 = steps[0], os = steps[1], n = dimensions[0]; char *i1 = args[0], *op = args[1]; c@typ@ *x, *y; @typ@ xr, xi, r, denom; for (i = 0; i < n; i++, i1 += is1, op += os) { x = (c@typ@ *)i1; y = (c@typ@ *)op; xr = x->real; xi = x->imag; if (fabs(xi) <= fabs(xr)) { r = xi / xr; denom = xr + xi * r; y->real = 1 / denom; y->imag = -r / denom; } else { r = xr / xi; denom = xr * r + xi; y->real = r / denom; y->imag = -1 / denom; } } } /**end repeat**/ static PyObject * Py_reciprocal(PyObject *o) { PyObject *one, *result; one = PyInt_FromLong(1); if (!one) return NULL; result = PyNumber_Divide(one, o); Py_DECREF(one); return result; } static PyObject * _npy_ObjectMax(PyObject *i1, PyObject *i2) { int cmp; PyObject *res; if (PyObject_Cmp(i1, i2, &cmp) < 0) return NULL; if (cmp >= 0) { res = i1; } else { res = i2; } Py_INCREF(res); return res; } static PyObject * _npy_ObjectMin(PyObject *i1, PyObject *i2) { int cmp; PyObject *res; if (PyObject_Cmp(i1, i2, &cmp) < 0) return NULL; if (cmp <= 0) { res = i1; } else { res = i2; } Py_INCREF(res); return res; } /* ones_like is defined here because it's used for x**0 */ /**begin repeat #TYP=BYTE,UBYTE,SHORT,USHORT,INT,UINT,LONG,ULONG,LONGLONG,ULONGLONG,FLOAT,DOUBLE,LONGDOUBLE# #typ=char, ubyte, short, ushort, int, uint, long, ulong, longlong, ulonglong, float, double, longdouble# */ static void @TYP@_ones_like(char **args, intp *dimensions, intp *steps, void *data) { intp i, os = steps[1], n = dimensions[0]; char *op = args[1]; for (i = 0; i < n; i++, op += os) { *((@typ@ *)op) = 1; } } /**end repeat**/ /**begin repeat #TYP=CFLOAT,CDOUBLE,CLONGDOUBLE# #typ=float, double, longdouble# */ static void @TYP@_ones_like(char **args, intp *dimensions, intp *steps, void *data) { intp i, is1 = steps[0], os = steps[1], n = dimensions[0]; char *i1 = args[0], *op = args[1]; c@typ@ *y; for (i = 0; i < n; i++, i1 += is1, op += os) { y = (c@typ@ *)op; y->real = 1.0; y->imag = 0.0; } } /**end repeat**/ static PyObject * Py_get_one(PyObject *o) { return PyInt_FromLong(1); } /**begin repeat #TYP=BYTE,UBYTE,SHORT,USHORT,INT,UINT,LONG,ULONG,LONGLONG,ULONGLONG# #typ=char, ubyte, short, ushort, int, uint, long, ulong, longlong, ulonglong# #btyp=float*4, double*6# */ static void @TYP@_power(char **args, intp *dimensions, intp *steps, void *func) { register intp i, is1=steps[0],is2=steps[1]; register intp os=steps[2], n=dimensions[0]; char *i1=args[0], *i2=args[1], *op=args[2]; @btyp@ x, y; for(i=0; i, >=, <, <=, ==, !=, &&, ||, &, |, ^# **/ static void BOOL_@kind@(char **args, intp *dimensions, intp *steps, void *func) { register intp i; intp is1=steps[0],is2=steps[1],os=steps[2], n=dimensions[0]; char *i1=args[0], *i2=args[1], *op=args[2]; Bool in1, in2; for(i=0; i*13, >=*13, <*13, <=*13# #typ=(byte, ubyte, short, ushort, int, uint, long, ulong, longlong, ulonglong, float, double, longdouble)*4# #kind= greater*13, greater_equal*13, less*13, less_equal*13# */ static void @TYPE@_@kind@(char **args, intp *dimensions, intp *steps, void *func) { register intp i; intp is1=steps[0],is2=steps[1],os=steps[2], n=dimensions[0]; char *i1=args[0], *i2=args[1], *op=args[2]; for(i=0; i*3, >=*3, <*3, <=*3# #typ=(cfloat, cdouble, clongdouble)*4# #kind= greater*3, greater_equal*3, less*3, less_equal*3# */ static void @TYPE@_@kind@(char **args, intp *dimensions, intp *steps, void *func) { register intp i; intp is1=steps[0],is2=steps[1],os=steps[2], n=dimensions[0]; char *i1=args[0], *i2=args[1], *op=args[2]; for(i=0; ireal == ((@typ@ *)i2)->real) *((Bool *)op)=((@typ@ *)i1)->imag @OP@ \ ((@typ@ *)i2)->imag; else *((Bool *)op)=((@typ@ *)i1)->real @OP@ \ ((@typ@ *)i2)->real; } } /**end repeat**/ /**begin repeat #TYPE=(BYTE,UBYTE,SHORT,USHORT,INT,UINT,LONG,ULONG,LONGLONG,ULONGLONG,FLOAT,DOUBLE,LONGDOUBLE)*4# #typ=(byte, ubyte, short, ushort, int, uint, long, ulong, longlong, ulonglong, float, double, longdouble)*4# #OP= ==*13, !=*13, &&*13, ||*13# #kind=equal*13, not_equal*13, logical_and*13, logical_or*13# */ static void @TYPE@_@kind@(char **args, intp *dimensions, intp *steps, void *func) { register intp i; intp is1=steps[0],is2=steps[1],os=steps[2], n=dimensions[0]; char *i1=args[0], *i2=args[1], *op=args[2]; for(i=0; i 0 ? 1 : ((x) < 0 ? -1 : 0)) #define _SIGN2(x) ((x) == 0 ? 0 : 1) #define _SIGNC(x) (((x).real > 0) ? 1 : ((x).real < 0 ? -1 : ((x).imag > 0 ? 1 : ((x).imag < 0) ? -1 : 0))) /**begin repeat #TYPE=BYTE,SHORT,INT,LONG,LONGLONG,FLOAT,DOUBLE,LONGDOUBLE,UBYTE,USHORT,UINT,ULONG,ULONGLONG# #typ=byte,short,int,long,longlong,float,double,longdouble,ubyte,ushort,uint,ulong,ulonglong# #func=_SIGN1*8,_SIGN2*5# */ static void @TYPE@_sign(char **args, intp *dimensions, intp *steps, void *func) { register intp i; intp is1=steps[0],os=steps[1], n=dimensions[0]; char *i1=args[0], *op=args[1]; @typ@ t1; for(i=0; ireal || \ ((@typ@ *)i1)->imag); } } /**end repeat**/ /**begin repeat #TYPE=BYTE,SHORT,INT,LONG,LONGLONG# #typ=byte, short, int, long, longlong# #c=f*2,,,l*1# */ static void @TYPE@_remainder(char **args, intp *dimensions, intp *steps, void *func) { register intp i; intp is1=steps[0],is2=steps[1],os=steps[2], n=dimensions[0]; char *i1=args[0], *i2=args[1], *op=args[2]; register @typ@ ix,iy, tmp; for(i=0; i 0) == (iy > 0)) { *((@typ@ *)op) = ix % iy; } else { /* handle mixed case the way Python does */ tmp = ix % iy; if (tmp) tmp += iy; *((@typ@ *)op)= tmp; } } } /**end repeat**/ /**begin repeat #TYPE=UBYTE,USHORT,UINT,ULONG,ULONGLONG# #typ=ubyte, ushort, uint, ulong, ulonglong# */ static void @TYPE@_remainder(char **args, intp *dimensions, intp *steps, void *func) { register intp i; intp is1=steps[0],is2=steps[1],os=steps[2], n=dimensions[0]; char *i1=args[0], *i2=args[1], *op=args[2]; register @typ@ ix,iy; for(i=0; i>*10# #kind=bitwise_and*10, bitwise_or*10, bitwise_xor*10, left_shift*10, right_shift*10# */ static void @TYPE@_@kind@(char **args, intp *dimensions, intp *steps, void *func) { register intp i; intp is1=steps[0],is2=steps[1],os=steps[2], n=dimensions[0]; register char *i1=args[0], *i2=args[1], *op=args[2]; for(i=0; ireal || ((@typ@ *)i1)->imag; p2 = ((@typ@ *)i2)->real || ((@typ@ *)i2)->imag; *((Bool *)op)= (p1 || p2) && !(p1 && p2); } } /**end repeat**/ /**begin repeat #TYPE=(BOOL,BYTE,UBYTE,SHORT,USHORT,INT,UINT,LONG,ULONG,LONGLONG,ULONGLONG,FLOAT,DOUBLE,LONGDOUBLE)*2# #OP= >*14, <*14# #typ=(Bool, byte, ubyte, short, ushort, int, uint, long, ulong, longlong, ulonglong, float, double, longdouble)*2# #kind= maximum*14, minimum*14# */ static void @TYPE@_@kind@(char **args, intp *dimensions, intp *steps, void *func) { register intp i; intp is1=steps[0],is2=steps[1],os=steps[2], n=dimensions[0]; char *i1=args[0], *i2=args[1], *op=args[2]; for(i=0; i*3, <*3# #typ=(cfloat, cdouble, clongdouble)*2# #kind= maximum*3, minimum*3# */ static void @TYPE@_@kind@(char **args, intp *dimensions, intp *steps, void *func) { register intp i; intp is1=steps[0],is2=steps[1],os=steps[2], n=dimensions[0]; char *i1=args[0], *i2=args[1], *op=args[2]; @typ@ *i1c, *i2c; for(i=0; ireal @OP@ i2c->real) || \ ((i1c->real==i2c->real) && (i1c->imag @OP@ i2c->imag))) memmove(op, i1, sizeof(@typ@)); else memmove(op, i2, sizeof(@typ@)); } } /**end repeat**/ /*** isinf, isinf, isfinite, signbit ***/ /**begin repeat #kind=isnan*3, isinf*3, isfinite*3, signbit*3# #TYPE=(FLOAT, DOUBLE, LONGDOUBLE)*4# #typ=(float, double, longdouble)*4# #c=(f,,l)*4# */ static void @TYPE@_@kind@(char **args, intp *dimensions, intp *steps, void *func) { register intp i; intp is=steps[0], os=steps[1], n=dimensions[0]; char *ip=args[0], *op=args[1]; for(i=0; i