diff --git a/Objects/floatobject.c b/Objects/floatobject.c --- a/Objects/floatobject.c +++ b/Objects/floatobject.c @@ -29,11 +29,18 @@ free_list is a singly-linked list of available PyFloatObjects, linked via abuse of their ob_type members. + + A range of common integral floats arount 0 is interned. Such floats + are surprisingly common in practice, particularly when working + with tabled data. */ #define BLOCK_SIZE 1000 /* 1K less typical malloc overhead */ #define BHEAD_SIZE 8 /* Enough for a 64-bit pointer */ #define N_FLOATOBJECTS ((BLOCK_SIZE - BHEAD_SIZE) / sizeof(PyFloatObject)) +#define INTERN_LOW -10 /* lowest integral float to intern */ +#define INTERN_HIGH 10 /* highest integral float to intern */ +#define N_INTERN (INTERN_HIGH - INTERN_LOW + 1) struct _floatblock { struct _floatblock *next; @@ -44,6 +51,7 @@ static PyFloatBlock *block_list = NULL; static PyFloatObject *free_list = NULL; +static PyObject *f_intern[N_INTERN > 0 ? N_INTERN : 1] = {0}; static PyFloatObject * fill_free_list(void) @@ -148,14 +156,52 @@ return floatinfo; } +static int float_is_positive_zero(double fval) +{ +#ifdef MS_WINDOWS + return _fpclass(fval) == _FPCLASS_PZ; +#else +#if defined HAVE_LONG_LONG + /* perform a bitwise compare. positive zero is all bits 0 */ + if (sizeof(PY_LONG_LONG) == sizeof(double)) + return *(PY_LONG_LONG*)&fval == 0; +#endif +#endif + /* we can't tell, so assume all zeros are negative, disabling + * internment for them + */ + return 0; +} + PyObject * PyFloat_FromDouble(double fval) { register PyFloatObject *op; + int ival; if (free_list == NULL) { if ((free_list = fill_free_list()) == NULL) return NULL; + if (!f_intern[0]) { + /* pre-intern floats */ + int i; + for(i = 0; i= INTERN_LOW && ival <= INTERN_HIGH) { + /* ignore the negative zero */ + if (ival != 0 || float_is_positive_zero(fval)) { + ival -= INTERN_LOW; + if (f_intern[ival]) { + Py_INCREF(f_intern[ival]); + return f_intern[ival]; + } + } + } + /* Inline PyObject_New */ op = free_list; free_list = (PyFloatObject *)Py_TYPE(op); @@ -1938,6 +1984,11 @@ int u; /* remaining unfreed floats per block */ int freelist_size = 0; + for (i=0; i