Make float a new style number type.

This commit is contained in:
Neil Schemenauer 2001-01-04 01:44:34 +00:00
parent 29bfc07183
commit 32117e5c29
1 changed files with 108 additions and 42 deletions

View File

@ -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