Make float a new style number type.
This commit is contained in:
parent
29bfc07183
commit
32117e5c29
|
@ -256,6 +256,38 @@ PyFloat_AsStringEx(char *buf, PyFloatObject *v, int precision)
|
|||
}
|
||||
}
|
||||
|
||||
/* Macro and helper that convert PyObject obj to a C double and store
|
||||
the value in dbl; this replaces the functionality of the coercion
|
||||
slot function */
|
||||
|
||||
#define CONVERT_TO_DOUBLE(obj, dbl) \
|
||||
if (PyFloat_Check(obj)) \
|
||||
dbl = PyFloat_AS_DOUBLE(obj); \
|
||||
else if (convert_to_double(&(obj), &(dbl)) < 0) \
|
||||
return obj;
|
||||
|
||||
static int
|
||||
convert_to_double(PyObject **v,
|
||||
double *dbl)
|
||||
{
|
||||
register PyObject *obj = *v;
|
||||
|
||||
if (PyInt_Check(obj)) {
|
||||
*dbl = (double)PyInt_AS_LONG(obj);
|
||||
}
|
||||
else if (PyLong_Check(obj)) {
|
||||
PyFPE_START_PROTECT("convert_to_double", {*v=NULL;return -1;})
|
||||
*dbl = PyLong_AsDouble(obj);
|
||||
PyFPE_END_PROTECT(result)
|
||||
}
|
||||
else {
|
||||
Py_INCREF(Py_NotImplemented);
|
||||
*v = Py_NotImplemented;
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Precisions used by repr() and str(), respectively.
|
||||
|
||||
The repr() precision (17 significant decimal digits) is the minimal number
|
||||
|
@ -314,6 +346,15 @@ float_compare(PyFloatObject *v, PyFloatObject *w)
|
|||
return (i < j) ? -1 : (i > j) ? 1 : 0;
|
||||
}
|
||||
|
||||
/* Needed for the new style number compare slots */
|
||||
static PyObject *
|
||||
float_cmp(PyObject *v, PyObject *w)
|
||||
{
|
||||
double a,b;
|
||||
CONVERT_TO_DOUBLE(v, a);
|
||||
CONVERT_TO_DOUBLE(w, b);
|
||||
return PyInt_FromLong((a < b) ? -1 : (a > b) ? 1 : 0);
|
||||
}
|
||||
|
||||
static long
|
||||
float_hash(PyFloatObject *v)
|
||||
|
@ -322,62 +363,69 @@ float_hash(PyFloatObject *v)
|
|||
}
|
||||
|
||||
static PyObject *
|
||||
float_add(PyFloatObject *v, PyFloatObject *w)
|
||||
float_add(PyObject *v, PyObject *w)
|
||||
{
|
||||
double result;
|
||||
double a,b;
|
||||
CONVERT_TO_DOUBLE(v, a);
|
||||
CONVERT_TO_DOUBLE(w, b);
|
||||
PyFPE_START_PROTECT("add", return 0)
|
||||
result = v->ob_fval + w->ob_fval;
|
||||
PyFPE_END_PROTECT(result)
|
||||
return PyFloat_FromDouble(result);
|
||||
a = a + b;
|
||||
PyFPE_END_PROTECT(a)
|
||||
return PyFloat_FromDouble(a);
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
float_sub(PyFloatObject *v, PyFloatObject *w)
|
||||
float_sub(PyObject *v, PyObject *w)
|
||||
{
|
||||
double result;
|
||||
double a,b;
|
||||
CONVERT_TO_DOUBLE(v, a);
|
||||
CONVERT_TO_DOUBLE(w, b);
|
||||
PyFPE_START_PROTECT("subtract", return 0)
|
||||
result = v->ob_fval - w->ob_fval;
|
||||
PyFPE_END_PROTECT(result)
|
||||
return PyFloat_FromDouble(result);
|
||||
a = a - b;
|
||||
PyFPE_END_PROTECT(a)
|
||||
return PyFloat_FromDouble(a);
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
float_mul(PyFloatObject *v, PyFloatObject *w)
|
||||
float_mul(PyObject *v, PyObject *w)
|
||||
{
|
||||
double result;
|
||||
|
||||
double a,b;
|
||||
CONVERT_TO_DOUBLE(v, a);
|
||||
CONVERT_TO_DOUBLE(w, b);
|
||||
PyFPE_START_PROTECT("multiply", return 0)
|
||||
result = v->ob_fval * w->ob_fval;
|
||||
PyFPE_END_PROTECT(result)
|
||||
return PyFloat_FromDouble(result);
|
||||
a = a * b;
|
||||
PyFPE_END_PROTECT(a)
|
||||
return PyFloat_FromDouble(a);
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
float_div(PyFloatObject *v, PyFloatObject *w)
|
||||
float_div(PyObject *v, PyObject *w)
|
||||
{
|
||||
double result;
|
||||
if (w->ob_fval == 0) {
|
||||
double a,b;
|
||||
CONVERT_TO_DOUBLE(v, a);
|
||||
CONVERT_TO_DOUBLE(w, b);
|
||||
if (b == 0.0) {
|
||||
PyErr_SetString(PyExc_ZeroDivisionError, "float division");
|
||||
return NULL;
|
||||
}
|
||||
PyFPE_START_PROTECT("divide", return 0)
|
||||
result = v->ob_fval / w->ob_fval;
|
||||
PyFPE_END_PROTECT(result)
|
||||
return PyFloat_FromDouble(result);
|
||||
a = a / b;
|
||||
PyFPE_END_PROTECT(a)
|
||||
return PyFloat_FromDouble(a);
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
float_rem(PyFloatObject *v, PyFloatObject *w)
|
||||
float_rem(PyObject *v, PyObject *w)
|
||||
{
|
||||
double vx, wx;
|
||||
double mod;
|
||||
wx = w->ob_fval;
|
||||
CONVERT_TO_DOUBLE(v, vx);
|
||||
CONVERT_TO_DOUBLE(w, wx);
|
||||
if (wx == 0.0) {
|
||||
PyErr_SetString(PyExc_ZeroDivisionError, "float modulo");
|
||||
return NULL;
|
||||
}
|
||||
PyFPE_START_PROTECT("modulo", return 0)
|
||||
vx = v->ob_fval;
|
||||
mod = fmod(vx, wx);
|
||||
/* note: checking mod*wx < 0 is incorrect -- underflows to
|
||||
0 if wx < sqrt(smallest nonzero double) */
|
||||
|
@ -389,17 +437,17 @@ float_rem(PyFloatObject *v, PyFloatObject *w)
|
|||
}
|
||||
|
||||
static PyObject *
|
||||
float_divmod(PyFloatObject *v, PyFloatObject *w)
|
||||
float_divmod(PyObject *v, PyObject *w)
|
||||
{
|
||||
double vx, wx;
|
||||
double div, mod, floordiv;
|
||||
wx = w->ob_fval;
|
||||
CONVERT_TO_DOUBLE(v, vx);
|
||||
CONVERT_TO_DOUBLE(w, wx);
|
||||
if (wx == 0.0) {
|
||||
PyErr_SetString(PyExc_ZeroDivisionError, "float divmod()");
|
||||
return NULL;
|
||||
}
|
||||
PyFPE_START_PROTECT("divmod", return 0)
|
||||
vx = v->ob_fval;
|
||||
mod = fmod(vx, wx);
|
||||
/* fmod is typically exact, so vx-mod is *mathematically* an
|
||||
exact multiple of wx. But this is fp arithmetic, and fp
|
||||
|
@ -437,7 +485,7 @@ static double powu(double x, long n)
|
|||
}
|
||||
|
||||
static PyObject *
|
||||
float_pow(PyFloatObject *v, PyObject *w, PyFloatObject *z)
|
||||
float_pow(PyObject *v, PyObject *w, PyObject *z)
|
||||
{
|
||||
double iv, iw, ix;
|
||||
long intw;
|
||||
|
@ -446,17 +494,18 @@ float_pow(PyFloatObject *v, PyObject *w, PyFloatObject *z)
|
|||
* long integers. Maybe something clever with logarithms could be done.
|
||||
* [AMK]
|
||||
*/
|
||||
iv = v->ob_fval;
|
||||
iw = ((PyFloatObject *)w)->ob_fval;
|
||||
CONVERT_TO_DOUBLE(v, iv);
|
||||
CONVERT_TO_DOUBLE(w, iw);
|
||||
intw = (long)iw;
|
||||
|
||||
/* Sort out special cases here instead of relying on pow() */
|
||||
if (iw == 0) { /* x**0 is 1, even 0**0 */
|
||||
PyFPE_START_PROTECT("pow", return NULL)
|
||||
if ((PyObject *)z != Py_None) {
|
||||
ix = fmod(1.0, z->ob_fval);
|
||||
if (ix != 0 && z->ob_fval < 0)
|
||||
ix += z->ob_fval;
|
||||
double iz;
|
||||
CONVERT_TO_DOUBLE(w, iz);
|
||||
ix=fmod(1.0, iz);
|
||||
if (ix!=0 && iz<0) ix+=iz;
|
||||
}
|
||||
else
|
||||
ix = 1.0;
|
||||
|
@ -501,15 +550,14 @@ float_pow(PyFloatObject *v, PyObject *w, PyFloatObject *z)
|
|||
return NULL;
|
||||
}
|
||||
if ((PyObject *)z != Py_None) {
|
||||
PyFPE_START_PROTECT("pow", return NULL)
|
||||
ix = fmod(ix, z->ob_fval); /* XXX To Be Rewritten */
|
||||
if (ix != 0 &&
|
||||
((iv < 0 && z->ob_fval > 0) ||
|
||||
(iv > 0 && z->ob_fval < 0)
|
||||
)) {
|
||||
ix += z->ob_fval;
|
||||
double iz;
|
||||
CONVERT_TO_DOUBLE(z, iz);
|
||||
PyFPE_START_PROTECT("pow", return 0)
|
||||
ix=fmod(ix, iz); /* XXX To Be Rewritten */
|
||||
if (ix!=0 && ((iv<0 && iz>0) || (iv>0 && iz<0) )) {
|
||||
ix+=iz;
|
||||
}
|
||||
PyFPE_END_PROTECT(ix)
|
||||
PyFPE_END_PROTECT(ix)
|
||||
}
|
||||
return PyFloat_FromDouble(ix);
|
||||
}
|
||||
|
@ -611,6 +659,20 @@ static PyNumberMethods float_as_number = {
|
|||
(unaryfunc)float_float, /*nb_float*/
|
||||
0, /*nb_oct*/
|
||||
0, /*nb_hex*/
|
||||
0, /*nb_inplace_add*/
|
||||
0, /*nb_inplace_subtract*/
|
||||
0, /*nb_inplace_multiply*/
|
||||
0, /*nb_inplace_divide*/
|
||||
0, /*nb_inplace_remainder*/
|
||||
0, /*nb_inplace_power*/
|
||||
0, /*nb_inplace_lshift*/
|
||||
0, /*nb_inplace_rshift*/
|
||||
0, /*nb_inplace_and*/
|
||||
0, /*nb_inplace_xor*/
|
||||
0, /*nb_inplace_or*/
|
||||
|
||||
/* New style slots: */
|
||||
(binaryfunc)float_cmp, /*nb_cmp*/
|
||||
};
|
||||
|
||||
PyTypeObject PyFloat_Type = {
|
||||
|
@ -631,6 +693,10 @@ PyTypeObject PyFloat_Type = {
|
|||
(hashfunc)float_hash, /*tp_hash*/
|
||||
0, /*tp_call*/
|
||||
(reprfunc)float_str, /*tp_str*/
|
||||
0, /*tp_getattro*/
|
||||
0, /*tp_setattro*/
|
||||
0, /*tp_as_buffer*/
|
||||
Py_TPFLAGS_NEWSTYLENUMBER /*tp_flags*/
|
||||
};
|
||||
|
||||
void
|
||||
|
|
Loading…
Reference in New Issue