Cd1f8227d5965eaf691a1e5da80f8171
Python的浮点数设计

Python的浮点数设计

上周我们讲完了Python中自身对于int类型的实现,PyIntObject及其类型信息PyInt_Type,那今天我们就赶紧趁热打铁来关注下Python中浮点数的设计。

需要注意的事,Python中的浮点数类型并不会区分doublefloat,而是都称之为PyFloatObject

PyFloatObject

老样子,我们从[floatobject.h/.c]中可以看出PyFloatObject对象的定义:

typedef struct {
    PyObject_HEAD
    double ob_fval;
} PyFloatObject;

结构非常清晰简单,如果你看过之前我们分析PyIntObject的文章就会发现它们无非就是存值的成员变量从long类型变成了double类型。

同样的,对应的PyFloat_Type的定义也是基本类似,只是对应的方法指向了float的自身实现而已,比如我们来看一下加法的实现:

static PyObject *
float_add(PyObject *v, PyObject *w)
{
    double a,b;
    CONVERT_TO_DOUBLE(v, a);
    CONVERT_TO_DOUBLE(w, b);
    PyFPE_START_PROTECT("add", return 0)
    a = a + b;
    PyFPE_END_PROTECT(a)
    return PyFloat_FromDouble(a);
}

可以看出,PyFloatObject的加法和PyIntObject基本上毫无区别,还是通过计算ob_fval进行两个浮点数的加法,返回一个全新的PyFloatObject

我们继续看下PyFloat_FromDouble这个构造方法,也非常简单:

PyObject *
PyFloat_FromDouble(double fval)
{
    register PyFloatObject *op;
    if (free_list == NULL) {
        if ((free_list = fill_free_list()) == NULL)
            return NULL;
    }
    /* Inline PyObject_New */
    op = free_list;
    free_list = (PyFloatObject *)Py_TYPE(op);
    (void)PyObject_INIT(op, &PyFloat_Type);
    op->ob_fval = fval;
    return (PyObject *) op;
}

我擦,是不是非常熟悉,和PyIntObject的构造一摸一样,连申请内存的函数名fill_free_list都不变,那是不是意味着PyFloatObjectPyIntObject采用了一样的内存管理方式呢?

#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))

struct _floatblock {
    struct _floatblock *next;
    PyFloatObject objects[N_FLOATOBJECTS];
};

typedef struct _floatblock PyFloatBlock;

static PyFloatBlock *block_list = NULL;
top Created with Sketch.