{人面不知何去处 桃花依旧笑春风}

py3源码[2]-整数

Posted in Uncategorized by interma on 2012/10/11

根据PEP 0237,Py3中已经没有int类型了,py3中的整数对象指的只有PyLongObject了(关于Py2.x中的PyIntObject,《Python源码剖析》介绍的很详细了)。

整数的相关操作都在long_as_number操作集中。

先回答上篇文章遗留的2个问题:
1,PyLongObject的digit ob_digit[1]的作用?
A:是一个常量数组头(PyLongObject是不可变对象,不用考虑多态增长),对象初始化时分配所需要的实际空间并确定数据长度保存在PyObject_VAR_HEAD的ob_size中(tips:每个ob_digit只用了15位表示数字,ob_size的正负表示PyLongObject的正负)。
分析详解

2,long类型如何实现任意大整数的运算?
“PyLongObject是不可变对象,不用考虑多态增长,对象初始化时分配所需要的实际空间并确定数据长度保存在PyObject_VAR_HEAD的ob_size中”。示例:
加法的很简单

//longobject.c
/* Add the absolute values of two long integers. */
//低位开始诸位相加
static PyLongObject *
x_add(PyLongObject *a, PyLongObject *b)
{
    Py_ssize_t size_a = ABS(Py_SIZE(a)), size_b = ABS(Py_SIZE(b));
    PyLongObject *z;
    Py_ssize_t i;
    digit carry = 0;

    /* Ensure a is the larger of the two: */
    if (size_a < size_b) {
        { PyLongObject *temp = a; a = b; b = temp; }
        { Py_ssize_t size_temp = size_a;
            size_a = size_b;
            size_b = size_temp; }
    }
    z = _PyLong_New(size_a+1);
    if (z == NULL)
        return NULL;
    for (i = 0; i < size_b; ++i) {
        carry += a->ob_digit[i] + b->ob_digit[i];
        z->ob_digit[i] = carry & PyLong_MASK;
        carry >>= PyLong_SHIFT;
    }
    for (; i < size_a; ++i) {
        carry += a->ob_digit[i];
        z->ob_digit[i] = carry & PyLong_MASK;
        carry >>= PyLong_SHIFT;
    }
    z->ob_digit[i] = carry;
    return long_normalize(z);
}

乘法则复杂很多,Karatsuba算法(O(n^2)=>O(n^1.58))。
分析详解

依然使用了类似PyIntObject实现中的小整数对象池

//longobject.c
#ifndef NSMALLPOSINTS
#define NSMALLPOSINTS           257
#endif
#ifndef NSMALLNEGINTS
#define NSMALLNEGINTS           5
#endif
/* Small integers are preallocated in this array so that they
   can be shared.
   The integers that are preallocated are those in the range
   -NSMALLNEGINTS (inclusive) to NSMALLPOSINTS (not inclusive).
*/
static PyLongObject small_ints[NSMALLNEGINTS + NSMALLPOSINTS];

tips:
1,int _PyLong_Init(void)
初始化了这个小整数对象池
2,PyObject * PyLong_FromLong(long ival)
展示了如何从c的long类型建立一个PyLong(小整数使用池,其他整数直接malloc)。

问题:
1,《Python源码剖析》提到的整数对象池block_list应该已经不存在了(因为PyLongObject为变长对象)。
既然没有池了,malloc/free会带来的不小性能损耗,这也许是py3性能损耗的一个方面:”Py3.0运行 pystone benchmark的速度比Py2.5慢30%。Guido认为Py3.0有极大的优化空间,在字符串和整形操作上可以取得很好的优化结果。”
另外:底层还有arena这层内存管理机制。

2,long_normalize是否会导致内存泄漏?

/* Normalize (remove leading zeros from) a long int object.
   Doesn't attempt to free the storage--in most cases, due to the nature
   of the algorithms used, this could save at most be one word anyway. */
static PyLongObject * long_normalize(register PyLongObject *v)

参考:
1,python内部细节实现好文:www.endless-loops.com/tag/python

Tagged with:

留下评论