JayKimDevolved's picture
JayKimDevolved/deepseek
c011401 verified
/* -*- c -*- */
/* The purpose of this module is to add faster math for array scalars
that does not go through the ufunc machinery
but still supports error-modes.
*/
#define NPY_NO_DEPRECATED_API NPY_API_VERSION
#include "Python.h"
#include "numpy/arrayobject.h"
#include "numpy/ufuncobject.h"
#include "numpy/arrayscalars.h"
#include "npy_pycompat.h"
#include "numpy/halffloat.h"
#include "scalarmathmodule.h"
/* Basic operations:
*
* BINARY:
*
* add, subtract, multiply, divide, remainder, divmod, power,
* floor_divide, true_divide
*
* lshift, rshift, and, or, xor (integers only)
*
* UNARY:
*
* negative, positive, absolute, nonzero, invert, int, long, float, oct, hex
*
*/
/**begin repeat
* #name = byte, short, int, long, longlong#
* #type = npy_byte, npy_short, npy_int, npy_long, npy_longlong#
*/
static void
@name@_ctype_add(@type@ a, @type@ b, @type@ *out) {
*out = a + b;
if ((*out^a) >= 0 || (*out^b) >= 0) {
return;
}
npy_set_floatstatus_overflow();
return;
}
static void
@name@_ctype_subtract(@type@ a, @type@ b, @type@ *out) {
*out = a - b;
if ((*out^a) >= 0 || (*out^~b) >= 0) {
return;
}
npy_set_floatstatus_overflow();
return;
}
/**end repeat**/
/**begin repeat
* #name = ubyte, ushort, uint, ulong, ulonglong#
* #type = npy_ubyte, npy_ushort, npy_uint, npy_ulong, npy_ulonglong#
*/
static void
@name@_ctype_add(@type@ a, @type@ b, @type@ *out) {
*out = a + b;
if (*out >= a && *out >= b) {
return;
}
npy_set_floatstatus_overflow();
return;
}
static void
@name@_ctype_subtract(@type@ a, @type@ b, @type@ *out) {
*out = a - b;
if (a >= b) {
return;
}
npy_set_floatstatus_overflow();
return;
}
/**end repeat**/
#ifndef NPY_SIZEOF_BYTE
#define NPY_SIZEOF_BYTE 1
#endif
/**begin repeat
*
* #name = byte, ubyte, short, ushort,
* int, uint, long, ulong#
* #type = npy_byte, npy_ubyte, npy_short, npy_ushort,
* npy_int, npy_uint, npy_long, npy_ulong#
* #big = npy_int, npy_uint, npy_int, npy_uint,
* npy_longlong, npy_ulonglong, npy_longlong, npy_ulonglong#
* #NAME = BYTE, UBYTE, SHORT, USHORT,
* INT, UINT, LONG, ULONG#
* #SIZENAME = BYTE*2, SHORT*2, INT*2, LONG*2#
* #SIZE = INT*4,LONGLONG*4#
* #neg = (1,0)*4#
*/
#if NPY_SIZEOF_@SIZE@ > NPY_SIZEOF_@SIZENAME@
static void
@name@_ctype_multiply(@type@ a, @type@ b, @type@ *out) {
@big@ temp;
temp = ((@big@) a) * ((@big@) b);
*out = (@type@) temp;
#if @neg@
if (temp > NPY_MAX_@NAME@ || temp < NPY_MIN_@NAME@)
#else
if (temp > NPY_MAX_@NAME@)
#endif
npy_set_floatstatus_overflow();
return;
}
#endif
/**end repeat**/
/**begin repeat
*
* #name = int, uint, long, ulong,
* longlong, ulonglong#
* #type = npy_int, npy_uint, npy_long, npy_ulong,
* npy_longlong, npy_ulonglong#
* #SIZE = INT*2, LONG*2, LONGLONG*2#
*/
#if NPY_SIZEOF_LONGLONG == NPY_SIZEOF_@SIZE@
static void
@name@_ctype_multiply(@type@ a, @type@ b, @type@ *out) {
if (npy_mul_with_overflow_@name@(out, a, b)) {
npy_set_floatstatus_overflow();
}
return;
}
#endif
/**end repeat**/
/**begin repeat
*
* #name = byte, ubyte, short, ushort, int, uint,
* long, ulong, longlong, ulonglong#
* #type = npy_byte, npy_ubyte, npy_short, npy_ushort, npy_int, npy_uint,
* npy_long, npy_ulong, npy_longlong, npy_ulonglong#
* #neg = (1,0)*5#
*/
static void
@name@_ctype_divide(@type@ a, @type@ b, @type@ *out) {
if (b == 0) {
npy_set_floatstatus_divbyzero();
*out = 0;
}
#if @neg@
else if (b == -1 && a < 0 && a == -a) {
npy_set_floatstatus_overflow();
*out = a / b;
}
#endif
else {
#if @neg@
@type@ tmp;
tmp = a / b;
if (((a > 0) != (b > 0)) && (a % b != 0)) {
tmp--;
}
*out = tmp;
#else
*out = a / b;
#endif
}
}
#define @name@_ctype_floor_divide @name@_ctype_divide
static void
@name@_ctype_remainder(@type@ a, @type@ b, @type@ *out) {
if (a == 0 || b == 0) {
if (b == 0) npy_set_floatstatus_divbyzero();
*out = 0;
return;
}
#if @neg@
else if ((a > 0) == (b > 0)) {
*out = a % b;
}
else {
/* handled like Python does */
*out = a % b;
if (*out) *out += b;
}
#else
*out = a % b;
#endif
}
/**end repeat**/
/**begin repeat
*
* #name = byte, ubyte, short, ushort, int, uint, long,
* ulong, longlong, ulonglong#
* #otyp = npy_float*4, npy_double*6#
*/
#define @name@_ctype_true_divide(a, b, out) \
*(out) = ((@otyp@) (a)) / ((@otyp@) (b));
/**end repeat**/
/* b will always be positive in this call */
/**begin repeat
*
* #name = byte, ubyte, short, ushort, int, uint,
* long, ulong, longlong, ulonglong#
* #type = npy_byte, npy_ubyte, npy_short, npy_ushort, npy_int, npy_uint,
* npy_long, npy_ulong, npy_longlong, npy_ulonglong#
* #upc = BYTE, UBYTE, SHORT, USHORT, INT, UINT,
* LONG, ULONG, LONGLONG, ULONGLONG#
*/
static void
@name@_ctype_power(@type@ a, @type@ b, @type@ *out) {
@type@ temp, ix, mult;
/* code from Python's intobject.c, with overflow checking removed. */
temp = a;
ix = 1;
while (b > 0) {
if (b & 1) {
@name@_ctype_multiply(ix, temp, &mult);
ix = mult;
if (temp == 0) {
break;
}
}
b >>= 1; /* Shift exponent down by 1 bit */
if (b==0) {
break;
}
/* Square the value of temp */
@name@_ctype_multiply(temp, temp, &mult);
temp = mult;
}
*out = ix;
}
/**end repeat**/
/* QUESTION: Should we check for overflow / underflow in (l,r)shift? */
/**begin repeat
* #name = byte, ubyte, short, ushort, int, uint,
* long, ulong, longlong, ulonglong#
* #type = npy_byte, npy_ubyte, npy_short, npy_ushort, npy_int, npy_uint,
* npy_long, npy_ulong, npy_longlong, npy_ulonglong#
*/
/**begin repeat1
* #oper = and, xor, or, lshift, rshift#
* #op = &, ^, |, <<, >>#
*/
#define @name@_ctype_@oper@(arg1, arg2, out) *(out) = (arg1) @op@ (arg2)
/**end repeat1**/
/**end repeat**/
/**begin repeat
* #name = float, double, longdouble#
* #type = npy_float, npy_double, npy_longdouble#
*/
static @type@ (*_basic_@name@_floor)(@type@);
static @type@ (*_basic_@name@_sqrt)(@type@);
static @type@ (*_basic_@name@_fmod)(@type@, @type@);
#define @name@_ctype_add(a, b, outp) *(outp) = a + b
#define @name@_ctype_subtract(a, b, outp) *(outp) = a - b
#define @name@_ctype_multiply(a, b, outp) *(outp) = a * b
#define @name@_ctype_divide(a, b, outp) *(outp) = a / b
#define @name@_ctype_true_divide @name@_ctype_divide
#define @name@_ctype_floor_divide(a, b, outp) \
*(outp) = _basic_@name@_floor((a) / (b))
/**end repeat**/
static npy_half (*_basic_half_floor)(npy_half);
static npy_half (*_basic_half_sqrt)(npy_half);
static npy_half (*_basic_half_fmod)(npy_half, npy_half);
#define half_ctype_add(a, b, outp) *(outp) = \
npy_float_to_half(npy_half_to_float(a) + npy_half_to_float(b))
#define half_ctype_subtract(a, b, outp) *(outp) = \
npy_float_to_half(npy_half_to_float(a) - npy_half_to_float(b))
#define half_ctype_multiply(a, b, outp) *(outp) = \
npy_float_to_half(npy_half_to_float(a) * npy_half_to_float(b))
#define half_ctype_divide(a, b, outp) *(outp) = \
npy_float_to_half(npy_half_to_float(a) / npy_half_to_float(b))
#define half_ctype_true_divide half_ctype_divide
#define half_ctype_floor_divide(a, b, outp) \
*(outp) = npy_float_to_half(_basic_float_floor(npy_half_to_float(a) / \
npy_half_to_float(b)))
/**begin repeat
* #name = cfloat, cdouble, clongdouble#
* #rname = float, double, longdouble#
* #rtype = npy_float, npy_double, npy_longdouble#
* #c = f,,l#
*/
#define @name@_ctype_add(a, b, outp) do{ \
(outp)->real = (a).real + (b).real; \
(outp)->imag = (a).imag + (b).imag; \
} while(0)
#define @name@_ctype_subtract(a, b, outp) do{ \
(outp)->real = (a).real - (b).real; \
(outp)->imag = (a).imag - (b).imag; \
} while(0)
#define @name@_ctype_multiply(a, b, outp) do{ \
(outp)->real = (a).real * (b).real - (a).imag * (b).imag; \
(outp)->imag = (a).real * (b).imag + (a).imag * (b).real; \
} while(0)
/* Note: complex division by zero must yield some complex inf */
#define @name@_ctype_divide(a, b, outp) do{ \
@rtype@ d = (b).real*(b).real + (b).imag*(b).imag; \
if (d != 0) { \
(outp)->real = ((a).real*(b).real + (a).imag*(b).imag)/d; \
(outp)->imag = ((a).imag*(b).real - (a).real*(b).imag)/d; \
} \
else { \
(outp)->real = (a).real/d; \
(outp)->imag = (a).imag/d; \
} \
} while(0)
#define @name@_ctype_true_divide @name@_ctype_divide
#define @name@_ctype_floor_divide(a, b, outp) do { \
(outp)->real = _basic_@rname@_floor \
(((a).real*(b).real + (a).imag*(b).imag) / \
((b).real*(b).real + (b).imag*(b).imag)); \
(outp)->imag = 0; \
} while(0)
/**end repeat**/
/**begin repeat
* #name = float, double, longdouble#
* #type = npy_float, npy_double, npy_longdouble#
*/
static void
@name@_ctype_remainder(@type@ a, @type@ b, @type@ *out) {
@type@ mod;
mod = _basic_@name@_fmod(a, b);
if (mod && (((b < 0) != (mod < 0)))) {
mod += b;
}
*out = mod;
}
/**end repeat**/
static void
half_ctype_remainder(npy_half a, npy_half b, npy_half *out) {
float mod, fa = npy_half_to_float(a), fb = npy_half_to_float(b);
mod = _basic_float_fmod(fa, fb);
if (mod && (((fb < 0) != (mod < 0)))) {
mod += fb;
}
*out = npy_float_to_half(mod);
}
/**begin repeat
* #name = byte, ubyte, short, ushort, int, uint, long, ulong,
* longlong, ulonglong, half, float, double, longdouble,
* cfloat, cdouble, clongdouble#
*/
#define @name@_ctype_divmod(a, b, out, out2) { \
@name@_ctype_floor_divide(a, b, out); \
@name@_ctype_remainder(a, b, out2); \
}
/**end repeat**/
/**begin repeat
* #name = float, double, longdouble#
* #type = npy_float, npy_double, npy_longdouble#
*/
static npy_@name@ (*_basic_@name@_pow)(@type@ a, @type@ b);
static void
@name@_ctype_power(@type@ a, @type@ b, @type@ *out)
{
*out = _basic_@name@_pow(a, b);
}
/**end repeat**/
static void
half_ctype_power(npy_half a, npy_half b, npy_half *out)
{
const npy_float af = npy_half_to_float(a);
const npy_float bf = npy_half_to_float(b);
const npy_float outf = _basic_float_pow(af,bf);
*out = npy_float_to_half(outf);
}
/**begin repeat
* #name = byte, ubyte, short, ushort, int, uint,
* long, ulong, longlong, ulonglong,
* float, double, longdouble#
* #type = npy_byte, npy_ubyte, npy_short, npy_ushort, npy_int, npy_uint,
* npy_long, npy_ulong, npy_longlong, npy_ulonglong,
* npy_float, npy_double, npy_longdouble#
* #uns = (0,1)*5,0*3#
*/
static void
@name@_ctype_negative(@type@ a, @type@ *out)
{
#if @uns@
npy_set_floatstatus_overflow();
#endif
*out = -a;
}
/**end repeat**/
static void
half_ctype_negative(npy_half a, npy_half *out)
{
*out = a^0x8000u;
}
/**begin repeat
* #name = cfloat, cdouble, clongdouble#
* #type = npy_cfloat, npy_cdouble, npy_clongdouble#
*/
static void
@name@_ctype_negative(@type@ a, @type@ *out)
{
out->real = -a.real;
out->imag = -a.imag;
}
/**end repeat**/
/**begin repeat
* #name = byte, ubyte, short, ushort, int, uint,
* long, ulong, longlong, ulonglong,
* half, float, double, longdouble#
* #type = npy_byte, npy_ubyte, npy_short, npy_ushort, npy_int, npy_uint,
* npy_long, npy_ulong, npy_longlong, npy_ulonglong,
* npy_half, npy_float, npy_double, npy_longdouble#
*/
static void
@name@_ctype_positive(@type@ a, @type@ *out)
{
*out = a;
}
/**end repeat**/
/*
* Get the nc_powf, nc_pow, and nc_powl functions from
* the data area of the power ufunc in umathmodule.
*/
/**begin repeat
* #name = cfloat, cdouble, clongdouble#
* #type = npy_cfloat, npy_cdouble, npy_clongdouble#
*/
static void
@name@_ctype_positive(@type@ a, @type@ *out)
{
out->real = a.real;
out->imag = a.imag;
}
static void (*_basic_@name@_pow)(@type@ *, @type@ *, @type@ *);
static void
@name@_ctype_power(@type@ a, @type@ b, @type@ *out)
{
_basic_@name@_pow(&a, &b, out);
}
/**end repeat**/
/**begin repeat
* #name = ubyte, ushort, uint, ulong, ulonglong#
*/
#define @name@_ctype_absolute @name@_ctype_positive
/**end repeat**/
/**begin repeat
* #name = byte, short, int, long, longlong,
* float, double, longdouble#
* #type = npy_byte, npy_short, npy_int, npy_long, npy_longlong,
* npy_float, npy_double, npy_longdouble#
*/
static void
@name@_ctype_absolute(@type@ a, @type@ *out)
{
*out = (a < 0 ? -a : a);
}
/**end repeat**/
static void
half_ctype_absolute(npy_half a, npy_half *out)
{
*out = a&0x7fffu;
}
/**begin repeat
* #name = cfloat, cdouble, clongdouble#
* #type = npy_cfloat, npy_cdouble, npy_clongdouble#
* #rname = float, double, longdouble#
* #rtype = npy_float, npy_double, npy_longdouble#
*/
static void
@name@_ctype_absolute(@type@ a, @rtype@ *out)
{
*out = _basic_@rname@_sqrt(a.real*a.real + a.imag*a.imag);
}
/**end repeat**/
/**begin repeat
* #name = byte, ubyte, short, ushort, int, uint, long,
* ulong, longlong, ulonglong#
*/
#define @name@_ctype_invert(a, out) *(out) = ~a;
/**end repeat**/
/*** END OF BASIC CODE **/
/* The general strategy for commutative binary operators is to
*
* 1) Convert the types to the common type if both are scalars (0 return)
* 2) If both are not scalars use ufunc machinery (-2 return)
* 3) If both are scalars but cannot be cast to the right type
* return NotImplmented (-1 return)
*
* 4) Perform the function on the C-type.
* 5) If an error condition occurred, check to see
* what the current error-handling is and handle the error.
*
* 6) Construct and return the output scalar.
*/
/**begin repeat
* #name = byte, ubyte, short, ushort, int, uint,
* long, ulong, longlong, ulonglong,
* half, float, longdouble,
* cfloat, cdouble, clongdouble#
* #type = npy_byte, npy_ubyte, npy_short, npy_ushort, npy_int, npy_uint,
* npy_long, npy_ulong, npy_longlong, npy_ulonglong,
* npy_half, npy_float, npy_longdouble,
* npy_cfloat, npy_cdouble, npy_clongdouble#
* #Name = Byte, UByte, Short, UShort, Int, UInt,
* Long, ULong, LongLong, ULongLong,
* Half, Float, LongDouble,
* CFloat, CDouble, CLongDouble#
* #TYPE = NPY_BYTE, NPY_UBYTE, NPY_SHORT, NPY_USHORT, NPY_INT, NPY_UINT,
* NPY_LONG, NPY_ULONG, NPY_LONGLONG, NPY_ULONGLONG,
* NPY_HALF, NPY_FLOAT, NPY_LONGDOUBLE,
* NPY_CFLOAT, NPY_CDOUBLE, NPY_CLONGDOUBLE#
*/
static int
_@name@_convert_to_ctype(PyObject *a, @type@ *arg1)
{
PyObject *temp;
if (PyArray_IsScalar(a, @Name@)) {
*arg1 = PyArrayScalar_VAL(a, @Name@);
return 0;
}
else if (PyArray_IsScalar(a, Generic)) {
PyArray_Descr *descr1;
if (!PyArray_IsScalar(a, Number)) {
return -1;
}
descr1 = PyArray_DescrFromTypeObject((PyObject *)Py_TYPE(a));
if (PyArray_CanCastSafely(descr1->type_num, @TYPE@)) {
PyArray_CastScalarDirect(a, descr1, arg1, @TYPE@);
Py_DECREF(descr1);
return 0;
}
else {
Py_DECREF(descr1);
return -1;
}
}
else if (PyArray_GetPriority(a, NPY_PRIORITY) > NPY_PRIORITY) {
return -2;
}
else if ((temp = PyArray_ScalarFromObject(a)) != NULL) {
int retval = _@name@_convert_to_ctype(temp, arg1);
Py_DECREF(temp);
return retval;
}
return -2;
}
/**end repeat**/
/* Same as above but added exact checks against known python types for speed */
/**begin repeat
* #name = double#
* #type = npy_double#
* #Name = Double#
* #TYPE = NPY_DOUBLE#
* #PYCHECKEXACT = PyFloat_CheckExact#
* #PYEXTRACTCTYPE = PyFloat_AS_DOUBLE#
*/
static int
_@name@_convert_to_ctype(PyObject *a, @type@ *arg1)
{
PyObject *temp;
if (@PYCHECKEXACT@(a)){
*arg1 = @PYEXTRACTCTYPE@(a);
return 0;
}
if (PyArray_IsScalar(a, @Name@)) {
*arg1 = PyArrayScalar_VAL(a, @Name@);
return 0;
}
else if (PyArray_IsScalar(a, Generic)) {
PyArray_Descr *descr1;
if (!PyArray_IsScalar(a, Number)) {
return -1;
}
descr1 = PyArray_DescrFromTypeObject((PyObject *)Py_TYPE(a));
if (PyArray_CanCastSafely(descr1->type_num, @TYPE@)) {
PyArray_CastScalarDirect(a, descr1, arg1, @TYPE@);
Py_DECREF(descr1);
return 0;
}
else {
Py_DECREF(descr1);
return -1;
}
}
else if (PyArray_GetPriority(a, NPY_PRIORITY) > NPY_PRIORITY) {
return -2;
}
else if ((temp = PyArray_ScalarFromObject(a)) != NULL) {
int retval = _@name@_convert_to_ctype(temp, arg1);
Py_DECREF(temp);
return retval;
}
return -2;
}
/**end repeat**/
/**begin repeat
* #name = byte, ubyte, short, ushort, int, uint,
* long, ulong, longlong, ulonglong,
* half, float, double, cfloat, cdouble#
* #type = npy_byte, npy_ubyte, npy_short, npy_ushort, npy_int, npy_uint,
* npy_long, npy_ulong, npy_longlong, npy_ulonglong,
* npy_half, npy_float, npy_double, npy_cfloat, npy_cdouble#
*/
static int
_@name@_convert2_to_ctypes(PyObject *a, @type@ *arg1,
PyObject *b, @type@ *arg2)
{
int ret;
ret = _@name@_convert_to_ctype(a, arg1);
if (ret < 0) {
return ret;
}
ret = _@name@_convert_to_ctype(b, arg2);
if (ret < 0) {
return ret;
}
return 0;
}
/**end repeat**/
/**begin repeat
* #name = longdouble, clongdouble#
* #type = npy_longdouble, npy_clongdouble#
*/
static int
_@name@_convert2_to_ctypes(PyObject *a, @type@ *arg1,
PyObject *b, @type@ *arg2)
{
int ret;
ret = _@name@_convert_to_ctype(a, arg1);
if (ret < 0) {
return ret;
}
ret = _@name@_convert_to_ctype(b, arg2);
if (ret == -2) {
ret = -3;
}
if (ret < 0) {
return ret;
}
return 0;
}
/**end repeat**/
#if defined(NPY_PY3K)
#define CODEGEN_SKIP_divide_FLAG
#endif
/**begin repeat
*
* #name = (byte, ubyte, short, ushort, int, uint,
* long, ulong, longlong, ulonglong)*13,
* (half, float, double, longdouble,
* cfloat, cdouble, clongdouble)*6,
* (half, float, double, longdouble)*2#
* #Name = (Byte, UByte, Short, UShort, Int, UInt,
* Long, ULong,LongLong,ULongLong)*13,
* (Half, Float, Double, LongDouble,
* CFloat, CDouble, CLongDouble)*6,
* (Half, Float, Double, LongDouble)*2#
* #type = (npy_byte, npy_ubyte, npy_short, npy_ushort, npy_int, npy_uint,
* npy_long, npy_ulong, npy_longlong, npy_ulonglong)*13,
* (npy_half, npy_float, npy_double, npy_longdouble,
* npy_cfloat, npy_cdouble, npy_clongdouble)*6,
* (npy_half, npy_float, npy_double, npy_longdouble)*2#
*
* #oper = add*10, subtract*10, multiply*10, divide*10, remainder*10,
* divmod*10, floor_divide*10, lshift*10, rshift*10, and*10,
* or*10, xor*10, true_divide*10,
* add*7, subtract*7, multiply*7, divide*7, floor_divide*7, true_divide*7,
* divmod*4, remainder*4#
*
* #fperr = 1*70,0*50,1*10,
* 1*42,
* 1*8#
* #twoout = 0*50,1*10,0*70,
* 0*42,
* 1*4,0*4#
* #otype = (npy_byte, npy_ubyte, npy_short, npy_ushort, npy_int, npy_uint,
* npy_long, npy_ulong, npy_longlong, npy_ulonglong)*12,
* npy_float*4, npy_double*6,
* (npy_half, npy_float, npy_double, npy_longdouble,
* npy_cfloat, npy_cdouble, npy_clongdouble)*6,
* (npy_half, npy_float, npy_double, npy_longdouble)*2#
* #OName = (Byte, UByte, Short, UShort, Int, UInt,
* Long, ULong, LongLong, ULongLong)*12,
* Float*4, Double*6,
* (Half, Float, Double, LongDouble,
* CFloat, CDouble, CLongDouble)*6,
* (Half, Float, Double, LongDouble)*2#
*/
#if !defined(CODEGEN_SKIP_@oper@_FLAG)
static PyObject *
@name@_@oper@(PyObject *a, PyObject *b)
{
PyObject *ret;
@type@ arg1, arg2;
/*
* NOTE: In gcc >= 4.1, the compiler will reorder floating point
* operations and floating point error state checks. In
* particular, the arithmetic operations were being reordered
* so that the errors weren't caught. Declaring this output
* variable volatile was the minimal fix for the issue.
* (Ticket #1671)
*/
volatile @otype@ out;
#if @twoout@
@otype@ out2;
PyObject *obj;
#endif
#if @fperr@
int retstatus;
int first;
#endif
switch(_@name@_convert2_to_ctypes(a, &arg1, b, &arg2)) {
case 0:
break;
case -1:
/* one of them can't be cast safely must be mixed-types*/
return PyArray_Type.tp_as_number->nb_@oper@(a,b);
case -2:
/* use default handling */
if (PyErr_Occurred()) {
return NULL;
}
return PyGenericArrType_Type.tp_as_number->nb_@oper@(a,b);
case -3:
/*
* special case for longdouble and clongdouble
* because they have a recursive getitem in their dtype
*/
Py_INCREF(Py_NotImplemented);
return Py_NotImplemented;
}
#if @fperr@
PyUFunc_clearfperr();
#endif
/*
* here we do the actual calculation with arg1 and arg2
* as a function call.
*/
#if @twoout@
@name@_ctype_@oper@(arg1, arg2, (@otype@ *)&out, &out2);
#else
@name@_ctype_@oper@(arg1, arg2, (@otype@ *)&out);
#endif
#if @fperr@
/* Check status flag. If it is set, then look up what to do */
retstatus = PyUFunc_getfperr();
if (retstatus) {
int bufsize, errmask;
PyObject *errobj;
if (PyUFunc_GetPyValues("@name@_scalars", &bufsize, &errmask,
&errobj) < 0) {
return NULL;
}
first = 1;
if (PyUFunc_handlefperr(errmask, errobj, retstatus, &first)) {
Py_XDECREF(errobj);
return NULL;
}
Py_XDECREF(errobj);
}
#endif
#if @twoout@
ret = PyTuple_New(2);
if (ret == NULL) {
return NULL;
}
obj = PyArrayScalar_New(@OName@);
if (obj == NULL) {
Py_DECREF(ret);
return NULL;
}
PyArrayScalar_ASSIGN(obj, @OName@, out);
PyTuple_SET_ITEM(ret, 0, obj);
obj = PyArrayScalar_New(@OName@);
if (obj == NULL) {
Py_DECREF(ret);
return NULL;
}
PyArrayScalar_ASSIGN(obj, @OName@, out2);
PyTuple_SET_ITEM(ret, 1, obj);
#else
ret = PyArrayScalar_New(@OName@);
if (ret == NULL) {
return NULL;
}
PyArrayScalar_ASSIGN(ret, @OName@, out);
#endif
return ret;
}
#endif
/**end repeat**/
#undef CODEGEN_SKIP_divide_FLAG
#define _IS_ZERO(x) (x == 0)
/**begin repeat
*
* #name = byte, ubyte, short, ushort, int, uint,
* long, ulong, longlong, ulonglong,
* half, float, double, longdouble,
* cfloat, cdouble, clongdouble#
*
* #type = npy_byte, npy_ubyte, npy_short, npy_ushort, npy_int, npy_uint,
* npy_long, npy_ulong, npy_longlong, npy_ulonglong,
* npy_half, npy_float, npy_double, npy_longdouble,
* npy_cfloat, npy_cdouble, npy_clongdouble#
*
* #Name = Byte, UByte, Short, UShort, Int, UInt,
* Long, ULong, LongLong, ULongLong,
* Half, Float, Double, LongDouble,
* CFloat, CDouble, CLongDouble#
*
* #otype = npy_float*4, npy_double*6, npy_half, npy_float,
* npy_double, npy_longdouble,
* npy_cfloat, npy_cdouble, npy_clongdouble#
*
* #OName = Float*4, Double*6, Half, Float,
* Double, LongDouble,
* CFloat, CDouble, CLongDouble#
*
* #isint = (1,0)*5,0*7#
* #cmplx = 0*14,1*3#
* #iszero = _IS_ZERO*10, npy_half_iszero, _IS_ZERO*6#
* #zero = 0*10, NPY_HALF_ZERO, 0*6#
* #one = 1*10, NPY_HALF_ONE, 1*6#
*/
#if @cmplx@
static PyObject *
@name@_power(PyObject *a, PyObject *b, PyObject *NPY_UNUSED(c))
{
PyObject *ret;
@type@ arg1, arg2;
int retstatus;
int first;
@type@ out = {@zero@, @zero@};
switch(_@name@_convert2_to_ctypes(a, &arg1, b, &arg2)) {
case 0:
break;
case -1:
/* can't cast both safely mixed-types? */
return PyArray_Type.tp_as_number->nb_power(a,b,NULL);
case -2:
/* use default handling */
if (PyErr_Occurred()) {
return NULL;
}
return PyGenericArrType_Type.tp_as_number->nb_power(a,b,NULL);
case -3:
/*
* special case for longdouble and clongdouble
* because they have a recursive getitem in their dtype
*/
Py_INCREF(Py_NotImplemented);
return Py_NotImplemented;
}
PyUFunc_clearfperr();
/*
* here we do the actual calculation with arg1 and arg2
* as a function call.
*/
if (@iszero@(arg2.real) && @iszero@(arg2.imag)) {
out.real = @one@;
out.imag = @zero@;
}
else {
@name@_ctype_power(arg1, arg2, &out);
}
/* Check status flag. If it is set, then look up what to do */
retstatus = PyUFunc_getfperr();
if (retstatus) {
int bufsize, errmask;
PyObject *errobj;
if (PyUFunc_GetPyValues("@name@_scalars", &bufsize, &errmask,
&errobj) < 0) {
return NULL;
}
first = 1;
if (PyUFunc_handlefperr(errmask, errobj, retstatus, &first)) {
Py_XDECREF(errobj);
return NULL;
}
Py_XDECREF(errobj);
}
ret = PyArrayScalar_New(@Name@);
if (ret == NULL) {
return NULL;
}
PyArrayScalar_ASSIGN(ret, @Name@, out);
return ret;
}
#elif @isint@
static PyObject *
@name@_power(PyObject *a, PyObject *b, PyObject *NPY_UNUSED(c))
{
PyObject *ret;
@type@ arg1, arg2;
int retstatus;
int first;
@type@ out = @zero@;
@otype@ out1 = @zero@;
switch(_@name@_convert2_to_ctypes(a, &arg1, b, &arg2)) {
case 0:
break;
case -1:
/* can't cast both safely mixed-types? */
return PyArray_Type.tp_as_number->nb_power(a,b,NULL);
case -2:
/* use default handling */
if (PyErr_Occurred()) {
return NULL;
}
return PyGenericArrType_Type.tp_as_number->nb_power(a,b,NULL);
case -3:
/*
* special case for longdouble and clongdouble
* because they have a recursive getitem in their dtype
*/
Py_INCREF(Py_NotImplemented);
return Py_NotImplemented;
}
PyUFunc_clearfperr();
/*
* here we do the actual calculation with arg1 and arg2
* as a function call.
*/
if (@iszero@(arg2)) {
out1 = out = @one@;
}
else if (arg2 < 0) {
@name@_ctype_power(arg1, -arg2, &out);
out1 = (@otype@) (1.0 / out);
}
else {
@name@_ctype_power(arg1, arg2, &out);
}
/* Check status flag. If it is set, then look up what to do */
retstatus = PyUFunc_getfperr();
if (retstatus) {
int bufsize, errmask;
PyObject *errobj;
if (PyUFunc_GetPyValues("@name@_scalars", &bufsize, &errmask,
&errobj) < 0) {
return NULL;
}
first = 1;
if (PyUFunc_handlefperr(errmask, errobj, retstatus, &first)) {
Py_XDECREF(errobj);
return NULL;
}
Py_XDECREF(errobj);
}
if (arg2 < 0) {
ret = PyArrayScalar_New(@OName@);
if (ret == NULL) {
return NULL;
}
PyArrayScalar_ASSIGN(ret, @OName@, out1);
}
else {
ret = PyArrayScalar_New(@Name@);
if (ret == NULL) {
return NULL;
}
PyArrayScalar_ASSIGN(ret, @Name@, out);
}
return ret;
}
#else
static PyObject *
@name@_power(PyObject *a, PyObject *b, PyObject *NPY_UNUSED(c))
{
PyObject *ret;
@type@ arg1, arg2;
int retstatus;
int first;
@type@ out = @zero@;
switch(_@name@_convert2_to_ctypes(a, &arg1, b, &arg2)) {
case 0:
break;
case -1:
/* can't cast both safely mixed-types? */
return PyArray_Type.tp_as_number->nb_power(a,b,NULL);
case -2:
/* use default handling */
if (PyErr_Occurred()) {
return NULL;
}
return PyGenericArrType_Type.tp_as_number->nb_power(a,b,NULL);
case -3:
/*
* special case for longdouble and clongdouble
* because they have a recursive getitem in their dtype
*/
Py_INCREF(Py_NotImplemented);
return Py_NotImplemented;
}
PyUFunc_clearfperr();
/*
* here we do the actual calculation with arg1 and arg2
* as a function call.
*/
if (@iszero@(arg2)) {
out = @one@;
}
else {
@name@_ctype_power(arg1, arg2, &out);
}
/* Check status flag. If it is set, then look up what to do */
retstatus = PyUFunc_getfperr();
if (retstatus) {
int bufsize, errmask;
PyObject *errobj;
if (PyUFunc_GetPyValues("@name@_scalars", &bufsize, &errmask,
&errobj) < 0) {
return NULL;
}
first = 1;
if (PyUFunc_handlefperr(errmask, errobj, retstatus, &first)) {
Py_XDECREF(errobj);
return NULL;
}
Py_XDECREF(errobj);
}
ret = PyArrayScalar_New(@Name@);
if (ret == NULL) {
return NULL;
}
PyArrayScalar_ASSIGN(ret, @Name@, out);
return ret;
}
#endif
/**end repeat**/
#undef _IS_ZERO
/**begin repeat
*
* #name = cfloat, cdouble, clongdouble#
*
*/
/**begin repeat1
*
* #oper = divmod, remainder#
*
*/
#define @name@_@oper@ NULL
/**end repeat1**/
/**end repeat**/
/**begin repeat
*
* #name = half, float, double, longdouble, cfloat, cdouble, clongdouble#
*
*/
/**begin repeat1
*
* #oper = lshift, rshift, and, or, xor#
*
*/
#define @name@_@oper@ NULL
/**end repeat1**/
/**end repeat**/
/**begin repeat
* #name = (byte, ubyte, short, ushort, int, uint,
* long, ulong, longlong, ulonglong,
* half, float, double, longdouble,
* cfloat, cdouble, clongdouble)*3,
*
* byte, ubyte, short, ushort, int, uint,
* long, ulong, longlong, ulonglong#
*
* #type = (npy_byte, npy_ubyte, npy_short, npy_ushort, npy_int, npy_uint,
* npy_long, npy_ulong, npy_longlong, npy_ulonglong,
* npy_half, npy_float, npy_double, npy_longdouble,
* npy_cfloat, npy_cdouble, npy_clongdouble)*3,
*
* npy_byte, npy_ubyte, npy_short, npy_ushort, npy_int, npy_uint,
* npy_long, npy_ulong, npy_longlong, npy_ulonglong#
*
* #otype = (npy_byte, npy_ubyte, npy_short, npy_ushort, npy_int, npy_uint,
* npy_long, npy_ulong, npy_longlong, npy_ulonglong,
* npy_half, npy_float, npy_double, npy_longdouble,
* npy_cfloat, npy_cdouble, npy_clongdouble)*2,
* npy_byte, npy_ubyte, npy_short, npy_ushort, npy_int, npy_uint,
* npy_long, npy_ulong, npy_longlong, npy_ulonglong,
* npy_half, npy_float, npy_double, npy_longdouble,
* npy_float, npy_double, npy_longdouble,
*
* npy_byte, npy_ubyte, npy_short, npy_ushort, npy_int, npy_uint,
* npy_long, npy_ulong, npy_longlong, npy_ulonglong#
*
* #OName = (Byte, UByte, Short, UShort, Int, UInt,
* Long, ULong, LongLong, ULongLong,
* Half, Float, Double, LongDouble,
* CFloat, CDouble, CLongDouble)*2,
* Byte, UByte, Short, UShort, Int, UInt,
* Long, ULong, LongLong, ULongLong,
* Half, Float, Double, LongDouble,
* Float, Double, LongDouble,
*
* Byte, UByte, Short, UShort, Int, UInt,
* Long, ULong, LongLong, ULongLong#
*
* #oper = negative*17, positive*17, absolute*17, invert*10#
*/
static PyObject *
@name@_@oper@(PyObject *a)
{
@type@ arg1;
@otype@ out;
PyObject *ret;
switch(_@name@_convert_to_ctype(a, &arg1)) {
case 0:
break;
case -1:
/* can't cast both safely use different add function */
Py_INCREF(Py_NotImplemented);
return Py_NotImplemented;
case -2:
/* use default handling */
if (PyErr_Occurred()) {
return NULL;
}
return PyGenericArrType_Type.tp_as_number->nb_@oper@(a);
}
/*
* here we do the actual calculation with arg1 and arg2
* make it a function call.
*/
@name@_ctype_@oper@(arg1, &out);
ret = PyArrayScalar_New(@OName@);
PyArrayScalar_ASSIGN(ret, @OName@, out);
return ret;
}
/**end repeat**/
/**begin repeat
*
* #name = half, float, double, longdouble, cfloat, cdouble, clongdouble#
*/
#define @name@_invert NULL
/**end repeat**/
#if defined(NPY_PY3K)
#define NONZERO_NAME(prefix) prefix##bool
#else
#define NONZERO_NAME(prefix) prefix##nonzero
#endif
#define _IS_NONZERO(x) (x != 0)
/**begin repeat
*
* #name = byte, ubyte, short, ushort, int,
* uint, long, ulong, longlong, ulonglong,
* half, float, double, longdouble,
* cfloat, cdouble, clongdouble#
* #type = npy_byte, npy_ubyte, npy_short, npy_ushort, npy_int,
* npy_uint, npy_long, npy_ulong, npy_longlong, npy_ulonglong,
* npy_half, npy_float, npy_double, npy_longdouble,
* npy_cfloat, npy_cdouble, npy_clongdouble#
* #simp = 1*14, 0*3#
* #nonzero = _IS_NONZERO*10, !npy_half_iszero, _IS_NONZERO*6#
*/
static int
NONZERO_NAME(@name@_)(PyObject *a)
{
int ret;
@type@ arg1;
if (_@name@_convert_to_ctype(a, &arg1) < 0) {
if (PyErr_Occurred()) {
return -1;
}
return PyGenericArrType_Type.tp_as_number->NONZERO_NAME(nb_)(a);
}
/*
* here we do the actual calculation with arg1 and arg2
* make it a function call.
*/
#if @simp@
ret = @nonzero@(arg1);
#else
ret = (@nonzero@(arg1.real) || @nonzero@(arg1.imag));
#endif
return ret;
}
/**end repeat**/
#undef _IS_NONZERO
static int
emit_complexwarning(void)
{
static PyObject *cls = NULL;
if (cls == NULL) {
PyObject *mod;
mod = PyImport_ImportModule("numpy.core");
assert(mod != NULL);
cls = PyObject_GetAttrString(mod, "ComplexWarning");
assert(cls != NULL);
Py_DECREF(mod);
}
return PyErr_WarnEx(cls,
"Casting complex values to real discards the imaginary part", 1);
}
/**begin repeat
*
* #name = byte, ubyte, short, ushort, int,
* uint, long, ulong, longlong, ulonglong,
* half, float, double, longdouble,
* cfloat, cdouble, clongdouble#
*
* #Name = Byte, UByte, Short, UShort, Int,
* UInt, Long, ULong, LongLong, ULongLong,
* Half, Float, Double, LongDouble,
* CFloat, CDouble, CLongDouble#
*
* #cmplx = 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1#
* #sign = (signed, unsigned)*5, , , , , , , #
* #unsigntyp = 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0*7#
* #ctype = long*8, PY_LONG_LONG*2, double*7#
* #to_ctype = , , , , , , , , , , npy_half_to_double, , , , , , #
* #realtyp = 0*10, 1*7#
* #func = (PyLong_FromLong, PyLong_FromUnsignedLong)*4,
* PyLong_FromLongLong, PyLong_FromUnsignedLongLong,
* PyLong_FromDouble*7#
*/
static PyObject *
@name@_int(PyObject *obj)
{
#if @cmplx@
@sign@ @ctype@ x= @to_ctype@(PyArrayScalar_VAL(obj, @Name@).real);
int ret;
#else
@sign@ @ctype@ x= @to_ctype@(PyArrayScalar_VAL(obj, @Name@));
#endif
#if @realtyp@
double ix;
modf(x, &ix);
x = ix;
#endif
#if @cmplx@
ret = emit_complexwarning();
if (ret < 0) {
return NULL;
}
#endif
#if @unsigntyp@
if(x < LONG_MAX)
return PyInt_FromLong(x);
#else
if(LONG_MIN < x && x < LONG_MAX)
return PyInt_FromLong(x);
#endif
return @func@(x);
}
/**end repeat**/
/**begin repeat
*
* #name = (byte, ubyte, short, ushort, int, uint,
* long, ulong, longlong, ulonglong,
* half, float, double, longdouble,
* cfloat, cdouble, clongdouble)*2#
* #Name = (Byte, UByte, Short, UShort, Int, UInt,
* Long, ULong, LongLong, ULongLong,
* Half, Float, Double, LongDouble,
* CFloat, CDouble, CLongDouble)*2#
* #cmplx = (0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1)*2#
* #to_ctype = (, , , , , , , , , , npy_half_to_double, , , , , , )*2#
* #which = long*17, float*17#
* #func = (PyLong_FromLongLong, PyLong_FromUnsignedLongLong)*5,
* PyLong_FromDouble*7, PyFloat_FromDouble*17#
*/
static PyObject *
@name@_@which@(PyObject *obj)
{
#if @cmplx@
int ret;
ret = emit_complexwarning();
if (ret < 0) {
return NULL;
}
return @func@(@to_ctype@((PyArrayScalar_VAL(obj, @Name@)).real));
#else
return @func@(@to_ctype@(PyArrayScalar_VAL(obj, @Name@)));
#endif
}
/**end repeat**/
#if !defined(NPY_PY3K)
/**begin repeat
*
* #name = (byte, ubyte, short, ushort, int, uint,
* long, ulong, longlong, ulonglong,
* half, float, double, longdouble,
* cfloat, cdouble, clongdouble)*2#
* #oper = oct*17, hex*17#
* #kind = (int*5, long*5, int*2, long*2, int, long*2)*2#
* #cap = (Int*5, Long*5, Int*2, Long*2, Int, Long*2)*2#
*/
static PyObject *
@name@_@oper@(PyObject *obj)
{
PyObject *pyint;
pyint = @name@_@kind@(obj);
if (pyint == NULL) {
return NULL;
}
return Py@cap@_Type.tp_as_number->nb_@oper@(pyint);
}
/**end repeat**/
#endif
/**begin repeat
* #oper = le, ge, lt, gt, eq, ne#
* #op = <=, >=, <, >, ==, !=#
* #halfop = npy_half_le, npy_half_ge, npy_half_lt,
* npy_half_gt, npy_half_eq, npy_half_ne#
*/
#define def_cmp_@oper@(arg1, arg2) (arg1 @op@ arg2)
#define cmplx_cmp_@oper@(arg1, arg2) ((arg1.real == arg2.real) ? \
arg1.imag @op@ arg2.imag : \
arg1.real @op@ arg2.real)
#define def_half_cmp_@oper@(arg1, arg2) @halfop@(arg1, arg2)
/**end repeat**/
/**begin repeat
* #name = byte, ubyte, short, ushort, int, uint,
* long, ulong, longlong, ulonglong,
* half, float, double, longdouble,
* cfloat, cdouble, clongdouble#
* #simp = def*10, def_half, def*3, cmplx*3#
*/
static PyObject*
@name@_richcompare(PyObject *self, PyObject *other, int cmp_op)
{
npy_@name@ arg1, arg2;
int out=0;
switch(_@name@_convert2_to_ctypes(self, &arg1, other, &arg2)) {
case 0:
break;
case -1:
/* can't cast both safely use different add function */
case -2:
/* use ufunc */
if (PyErr_Occurred()) {
return NULL;
}
return PyGenericArrType_Type.tp_richcompare(self, other, cmp_op);
case -3:
/*
* special case for longdouble and clongdouble
* because they have a recursive getitem in their dtype
*/
Py_INCREF(Py_NotImplemented);
return Py_NotImplemented;
}
/* here we do the actual calculation with arg1 and arg2 */
switch (cmp_op) {
case Py_EQ:
out = @simp@_cmp_eq(arg1, arg2);
break;
case Py_NE:
out = @simp@_cmp_ne(arg1, arg2);
break;
case Py_LE:
out = @simp@_cmp_le(arg1, arg2);
break;
case Py_GE:
out = @simp@_cmp_ge(arg1, arg2);
break;
case Py_LT:
out = @simp@_cmp_lt(arg1, arg2);
break;
case Py_GT:
out = @simp@_cmp_gt(arg1, arg2);
break;
}
if (out) {
PyArrayScalar_RETURN_TRUE;
}
else {
PyArrayScalar_RETURN_FALSE;
}
}
/**end repeat**/
/**begin repeat
* #name = byte, ubyte, short, ushort, int, uint,
* long, ulong, longlong, ulonglong,
* half, float, double, longdouble,
* cfloat, cdouble, clongdouble#
**/
static PyNumberMethods @name@_as_number = {
(binaryfunc)@name@_add, /*nb_add*/
(binaryfunc)@name@_subtract, /*nb_subtract*/
(binaryfunc)@name@_multiply, /*nb_multiply*/
#if defined(NPY_PY3K)
#else
(binaryfunc)@name@_divide, /*nb_divide*/
#endif
(binaryfunc)@name@_remainder, /*nb_remainder*/
(binaryfunc)@name@_divmod, /*nb_divmod*/
(ternaryfunc)@name@_power, /*nb_power*/
(unaryfunc)@name@_negative,
(unaryfunc)@name@_positive, /*nb_pos*/
(unaryfunc)@name@_absolute, /*nb_abs*/
#if defined(NPY_PY3K)
(inquiry)@name@_bool, /*nb_bool*/
#else
(inquiry)@name@_nonzero, /*nb_nonzero*/
#endif
(unaryfunc)@name@_invert, /*nb_invert*/
(binaryfunc)@name@_lshift, /*nb_lshift*/
(binaryfunc)@name@_rshift, /*nb_rshift*/
(binaryfunc)@name@_and, /*nb_and*/
(binaryfunc)@name@_xor, /*nb_xor*/
(binaryfunc)@name@_or, /*nb_or*/
#if defined(NPY_PY3K)
#else
0, /*nb_coerce*/
#endif
(unaryfunc)@name@_int, /*nb_int*/
#if defined(NPY_PY3K)
(unaryfunc)0, /*nb_reserved*/
#else
(unaryfunc)@name@_long, /*nb_long*/
#endif
(unaryfunc)@name@_float, /*nb_float*/
#if defined(NPY_PY3K)
#else
(unaryfunc)@name@_oct, /*nb_oct*/
(unaryfunc)@name@_hex, /*nb_hex*/
#endif
0, /*inplace_add*/
0, /*inplace_subtract*/
0, /*inplace_multiply*/
#if defined(NPY_PY3K)
#else
0, /*inplace_divide*/
#endif
0, /*inplace_remainder*/
0, /*inplace_power*/
0, /*inplace_lshift*/
0, /*inplace_rshift*/
0, /*inplace_and*/
0, /*inplace_xor*/
0, /*inplace_or*/
(binaryfunc)@name@_floor_divide, /*nb_floor_divide*/
(binaryfunc)@name@_true_divide, /*nb_true_divide*/
0, /*nb_inplace_floor_divide*/
0, /*nb_inplace_true_divide*/
(unaryfunc)NULL, /*nb_index*/
};
/**end repeat**/
static void *saved_tables_arrtype[9];
static void
add_scalarmath(void)
{
/**begin repeat
* #name = byte, ubyte, short, ushort, int, uint,
* long, ulong, longlong, ulonglong,
* half, float, double, longdouble,
* cfloat, cdouble, clongdouble#
* #NAME = Byte, UByte, Short, UShort, Int, UInt,
* Long, ULong, LongLong, ULongLong,
* Half, Float, Double, LongDouble,
* CFloat, CDouble, CLongDouble#
**/
@name@_as_number.nb_index = Py@NAME@ArrType_Type.tp_as_number->nb_index;
Py@NAME@ArrType_Type.tp_as_number = &(@name@_as_number);
Py@NAME@ArrType_Type.tp_richcompare = @name@_richcompare;
/**end repeat**/
saved_tables_arrtype[0] = PyLongArrType_Type.tp_as_number;
#if !defined(NPY_PY3K)
saved_tables_arrtype[1] = PyLongArrType_Type.tp_compare;
#endif
saved_tables_arrtype[2] = PyLongArrType_Type.tp_richcompare;
saved_tables_arrtype[3] = PyDoubleArrType_Type.tp_as_number;
#if !defined(NPY_PY3K)
saved_tables_arrtype[4] = PyDoubleArrType_Type.tp_compare;
#endif
saved_tables_arrtype[5] = PyDoubleArrType_Type.tp_richcompare;
saved_tables_arrtype[6] = PyCDoubleArrType_Type.tp_as_number;
#if !defined(NPY_PY3K)
saved_tables_arrtype[7] = PyCDoubleArrType_Type.tp_compare;
#endif
saved_tables_arrtype[8] = PyCDoubleArrType_Type.tp_richcompare;
}
static int
get_functions(void)
{
PyObject *mm, *obj;
void **funcdata;
char *signatures;
int i, j;
int ret = -1;
/* Get the nc_pow functions */
/* Get the pow functions */
mm = PyImport_ImportModule("numpy.core.umath");
if (mm == NULL) {
return -1;
}
obj = PyObject_GetAttrString(mm, "power");
if (obj == NULL) {
goto fail;
}
funcdata = ((PyUFuncObject *)obj)->data;
signatures = ((PyUFuncObject *)obj)->types;
i = 0;
j = 0;
while (signatures[i] != NPY_FLOAT) {
i += 3;
j++;
}
_basic_float_pow = funcdata[j];
_basic_double_pow = funcdata[j + 1];
_basic_longdouble_pow = funcdata[j + 2];
_basic_cfloat_pow = funcdata[j + 3];
_basic_cdouble_pow = funcdata[j + 4];
_basic_clongdouble_pow = funcdata[j + 5];
Py_DECREF(obj);
/* Get the floor functions */
obj = PyObject_GetAttrString(mm, "floor");
if (obj == NULL) {
goto fail;
}
funcdata = ((PyUFuncObject *)obj)->data;
signatures = ((PyUFuncObject *)obj)->types;
i = 0;
j = 0;
while(signatures[i] != NPY_FLOAT) {
i += 2;
j++;
}
_basic_half_floor = funcdata[j - 1];
_basic_float_floor = funcdata[j];
_basic_double_floor = funcdata[j + 1];
_basic_longdouble_floor = funcdata[j + 2];
Py_DECREF(obj);
/* Get the sqrt functions */
obj = PyObject_GetAttrString(mm, "sqrt");
if (obj == NULL) {
goto fail;
}
funcdata = ((PyUFuncObject *)obj)->data;
signatures = ((PyUFuncObject *)obj)->types;
/*
* sqrt ufunc is specialized for double and float loops in
* generate_umath.py, the first to go into FLOAT/DOUBLE_sqrt
* they have the same signature as the scalar variants so we need to skip
* over them
*/
i = 4;
j = 2;
while (signatures[i] != NPY_FLOAT) {
i += 2; j++;
}
_basic_half_sqrt = funcdata[j - 1];
_basic_float_sqrt = funcdata[j];
_basic_double_sqrt = funcdata[j + 1];
_basic_longdouble_sqrt = funcdata[j + 2];
Py_DECREF(obj);
/* Get the fmod functions */
obj = PyObject_GetAttrString(mm, "fmod");
if (obj == NULL) {
goto fail;
}
funcdata = ((PyUFuncObject *)obj)->data;
signatures = ((PyUFuncObject *)obj)->types;
i = 0;
j = 0;
while (signatures[i] != NPY_FLOAT) {
i += 3;
j++;
}
_basic_half_fmod = funcdata[j - 1];
_basic_float_fmod = funcdata[j];
_basic_double_fmod = funcdata[j + 1];
_basic_longdouble_fmod = funcdata[j + 2];
Py_DECREF(obj);
return ret = 0;
fail:
Py_DECREF(mm);
return ret;
}
static void *saved_tables[9];
char doc_alterpyscalars[] = "";
static PyObject *
alter_pyscalars(PyObject *NPY_UNUSED(dummy), PyObject *args)
{
int n;
PyObject *obj;
n = PyTuple_GET_SIZE(args);
while (n--) {
obj = PyTuple_GET_ITEM(args, n);
#if !defined(NPY_PY3K)
if (obj == (PyObject *)(&PyInt_Type)) {
PyInt_Type.tp_as_number = PyLongArrType_Type.tp_as_number;
PyInt_Type.tp_compare = PyLongArrType_Type.tp_compare;
PyInt_Type.tp_richcompare = PyLongArrType_Type.tp_richcompare;
}
else
#endif
if (obj == (PyObject *)(&PyFloat_Type)) {
PyFloat_Type.tp_as_number = PyDoubleArrType_Type.tp_as_number;
#if !defined(NPY_PY3K)
PyFloat_Type.tp_compare = PyDoubleArrType_Type.tp_compare;
#endif
PyFloat_Type.tp_richcompare = PyDoubleArrType_Type.tp_richcompare;
}
else if (obj == (PyObject *)(&PyComplex_Type)) {
PyComplex_Type.tp_as_number = PyCDoubleArrType_Type.tp_as_number;
#if !defined(NPY_PY3K)
PyComplex_Type.tp_compare = PyCDoubleArrType_Type.tp_compare;
#endif
PyComplex_Type.tp_richcompare = \
PyCDoubleArrType_Type.tp_richcompare;
}
else {
PyErr_SetString(PyExc_ValueError,
"arguments must be int, float, or complex");
return NULL;
}
}
Py_INCREF(Py_None);
return Py_None;
}
char doc_restorepyscalars[] = "";
static PyObject *
restore_pyscalars(PyObject *NPY_UNUSED(dummy), PyObject *args)
{
int n;
PyObject *obj;
n = PyTuple_GET_SIZE(args);
while (n--) {
obj = PyTuple_GET_ITEM(args, n);
#if !defined(NPY_PY3K)
if (obj == (PyObject *)(&PyInt_Type)) {
PyInt_Type.tp_as_number = saved_tables[0];
PyInt_Type.tp_compare = saved_tables[1];
PyInt_Type.tp_richcompare = saved_tables[2];
}
else
#endif
if (obj == (PyObject *)(&PyFloat_Type)) {
PyFloat_Type.tp_as_number = saved_tables[3];
#if !defined(NPY_PY3K)
PyFloat_Type.tp_compare = saved_tables[4];
#endif
PyFloat_Type.tp_richcompare = saved_tables[5];
}
else if (obj == (PyObject *)(&PyComplex_Type)) {
PyComplex_Type.tp_as_number = saved_tables[6];
#if !defined(NPY_PY3K)
PyComplex_Type.tp_compare = saved_tables[7];
#endif
PyComplex_Type.tp_richcompare = saved_tables[8];
}
else {
PyErr_SetString(PyExc_ValueError,
"arguments must be int, float, or complex");
return NULL;
}
}
Py_INCREF(Py_None);
return Py_None;
}
char doc_usepythonmath[] = "";
static PyObject *
use_pythonmath(PyObject *NPY_UNUSED(dummy), PyObject *args)
{
int n;
PyObject *obj;
n = PyTuple_GET_SIZE(args);
while (n--) {
obj = PyTuple_GET_ITEM(args, n);
#if !defined(NPY_PY3K)
if (obj == (PyObject *)(&PyInt_Type)) {
PyLongArrType_Type.tp_as_number = saved_tables[0];
PyLongArrType_Type.tp_compare = saved_tables[1];
PyLongArrType_Type.tp_richcompare = saved_tables[2];
}
else
#endif
if (obj == (PyObject *)(&PyFloat_Type)) {
PyDoubleArrType_Type.tp_as_number = saved_tables[3];
#if !defined(NPY_PY3K)
PyDoubleArrType_Type.tp_compare = saved_tables[4];
#endif
PyDoubleArrType_Type.tp_richcompare = saved_tables[5];
}
else if (obj == (PyObject *)(&PyComplex_Type)) {
PyCDoubleArrType_Type.tp_as_number = saved_tables[6];
#if !defined(NPY_PY3K)
PyCDoubleArrType_Type.tp_compare = saved_tables[7];
#endif
PyCDoubleArrType_Type.tp_richcompare = saved_tables[8];
}
else {
PyErr_SetString(PyExc_ValueError,
"arguments must be int, float, or complex");
return NULL;
}
}
Py_INCREF(Py_None);
return Py_None;
}
char doc_usescalarmath[] = "";
static PyObject *
use_scalarmath(PyObject *NPY_UNUSED(dummy), PyObject *args)
{
int n;
PyObject *obj;
n = PyTuple_GET_SIZE(args);
while (n--) {
obj = PyTuple_GET_ITEM(args, n);
#if !defined(NPY_PY3K)
if (obj == (PyObject *)(&PyInt_Type)) {
PyLongArrType_Type.tp_as_number = saved_tables_arrtype[0];
PyLongArrType_Type.tp_compare = saved_tables_arrtype[1];
PyLongArrType_Type.tp_richcompare = saved_tables_arrtype[2];
}
else
#endif
if (obj == (PyObject *)(&PyFloat_Type)) {
PyDoubleArrType_Type.tp_as_number = saved_tables_arrtype[3];
#if !defined(NPY_PY3K)
PyDoubleArrType_Type.tp_compare = saved_tables_arrtype[4];
#endif
PyDoubleArrType_Type.tp_richcompare = saved_tables_arrtype[5];
}
else if (obj == (PyObject *)(&PyComplex_Type)) {
PyCDoubleArrType_Type.tp_as_number = saved_tables_arrtype[6];
#if !defined(NPY_PY3K)
PyCDoubleArrType_Type.tp_compare = saved_tables_arrtype[7];
#endif
PyCDoubleArrType_Type.tp_richcompare = saved_tables_arrtype[8];
}
else {
PyErr_SetString(PyExc_ValueError,
"arguments must be int, float, or complex");
return NULL;
}
}
Py_INCREF(Py_None);
return Py_None;
}
static struct PyMethodDef methods[] = {
{"alter_pythonmath",
(PyCFunction) alter_pyscalars,
METH_VARARGS, doc_alterpyscalars},
{"restore_pythonmath",
(PyCFunction) restore_pyscalars,
METH_VARARGS, doc_restorepyscalars},
{"use_pythonmath",
(PyCFunction) use_pythonmath,
METH_VARARGS, doc_usepythonmath},
{"use_scalarmath",
(PyCFunction) use_scalarmath,
METH_VARARGS, doc_usescalarmath},
{NULL, NULL, 0, NULL}
};
#if defined(NPY_PY3K)
static struct PyModuleDef moduledef = {
PyModuleDef_HEAD_INIT,
"scalarmath",
NULL,
-1,
methods,
NULL,
NULL,
NULL,
NULL
};
#endif
#if defined(NPY_PY3K)
#define RETVAL m
PyMODINIT_FUNC PyInit_scalarmath(void)
#else
#define RETVAL
PyMODINIT_FUNC
initscalarmath(void)
#endif
{
#if defined(NPY_PY3K)
PyObject *m = PyModule_Create(&moduledef);
if (!m) {
return NULL;
}
#else
Py_InitModule("scalarmath", methods);
#endif
import_array();
import_umath();
if (get_functions() < 0) {
return RETVAL;
}
add_scalarmath();
#if !defined(NPY_PY3K)
saved_tables[0] = PyInt_Type.tp_as_number;
saved_tables[1] = PyInt_Type.tp_compare;
saved_tables[2] = PyInt_Type.tp_richcompare;
#endif
saved_tables[3] = PyFloat_Type.tp_as_number;
#if !defined(NPY_PY3K)
saved_tables[4] = PyFloat_Type.tp_compare;
#endif
saved_tables[5] = PyFloat_Type.tp_richcompare;
saved_tables[6] = PyComplex_Type.tp_as_number;
#if !defined(NPY_PY3K)
saved_tables[7] = PyComplex_Type.tp_compare;
#endif
saved_tables[8] = PyComplex_Type.tp_richcompare;
return RETVAL;
}