出现比较频繁的整数,我们把它放入小整数池,小整数池外边的整数,我们称为大整数。大整数是用digit数组实现的,就决定了大整数进行数学运算时难度比较大,看一下Cpython中如何实现的。
整数加法在源码中:cpython-masterObjectslongobject.c
static PyObject *
long_add(PyLongObject *a, PyLongObject *b)
{
//定义z,用于保存a+b的临时对象
PyLongObject *z;
//检查ab是不是都指向PyLongObject
CHECK_BINOP(a, b);
//ab的 ob_size的绝对值是否都小于等于1;如是0,说明整数是0;如是1,一个元素,直接取出来。
//快速分支,大部分整数在这个分支截止
if (Py_ABS(Py_SIZE(a)) <= 1 && Py_ABS(Py_SIZE(b)) <= 1) {
//MEDIUM_VALUE拿出整数0或者digit[0] 0]
return PyLong_FromLong(MEDIUM_VALUE(a) + MEDIUM_VALUE(b));
}
if (Py_SIZE(a) < 0) {
if (Py_SIZE(b) < 0) {
z = x_add(a, b);
if (z != NULL) {
/* x_add received at least one multiple-digit int,
and thus z must be a multiple-digit int.
That also means z is not an element of
small_ints, so negating it in-place is safe. */
assert(Py_REFCNT(z) == 1);
Py_SET_SIZE(z, -(Py_SIZE(z)));
}
}
else
z = x_sub(b, a);
}
else {
if (Py_SIZE(b) < 0)
z = x_sub(a, b);
else
z = x_add(a, b);
}
return (PyObject *)z;
}
long_add里边的if-else逻辑如下:
将整数运算转换为整数绝对值运算,下边我们重点看两个整数绝对值是如何计算的
cpython-masterObjectslongobject.c
绝对值相加:
static PyLongObject *
x_add(PyLongObject *a, PyLongObject *b)
{
//获取a、b的ob_size的绝对值
Py_ssize_t size_a = Py_ABS(Py_SIZE(a)), size_b = Py_ABS(Py_SIZE(b));
//a、b的临时结果存储
PyLongObject *z;
//循环变量
Py_ssize_t i;
//每个部分的运算结果
digit carry = 0;
//如果size_a < size_b,将a、b交换,将a、b的size交换
//相加按照相关,大的放在上边,小的放在下边,从右到左相加
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; }
}
//如果size_a >= size_b,则不需要交换
z = _PyLong_New(size_a+1);//考虑进位,长度比a和b中最大的加1
if (z == NULL)
return NULL;
for (i = 0; i < size_b; ++i) {//以b->ob_size为基准先遍历
carry += a->ob_digit[i] + b->ob_digit[i];
z->ob_digit[i] = carry & PyLong_MASK;//保证 z->ob_digit[i]不超过30位
carry >>= PyLong_SHIFT;//超出部分用于i+1,i+1比i多30位
}
for (; i < size_a; ++i) {//遍历完b之后,只剩a了
carry += a->ob_digit[i];
z->ob_digit[i] = carry & PyLong_MASK;//保证 z->ob_digit[i]不超过30位
carry >>= PyLong_SHIFT;//超出部分用于i+1,i+1比i多30位
}
z->ob_digit[i] = carry;//加上最后的进位
return long_normalize(z);//这个long_normalize函数作用就是从后往前依次检查ob_digit的元素,
//如果为0, 那么就将其ob_size减去1, 直到出现一个不为0的元素
}
PyLong_MASK// (1<<30)-1 = 2^30 - 1 说明后面30个位是1,前边两个位是0.
cpython-masterObjectslongobject.c
绝对值相减:
static PyLongObject *
x_sub(PyLongObject *a, PyLongObject *b)
{
//获取a、b的ob_size的绝对值
Py_ssize_t size_a = Py_ABS(Py_SIZE(a)), size_b = Py_ABS(Py_SIZE(b));
PyLongObject *z;//中间临时变量
Py_ssize_t i; //循环变量
int sign = 1;//size_a > size_b 为1 否则就是-1
digit borrow = 0; //保存相减的结果
//确保a是两者中的大数
if (size_a < size_b) {
sign = -1; //交换只有改变符号
{ PyLongObject *temp = a; a = b; b = temp; }
{ Py_ssize_t size_temp = size_a;
size_a = size_b;
size_b = size_temp; }
}
else if (size_a == size_b) {//a、b的size相等,看一下里边的值是否也相等呢
/* Find highest digit where a and b differ: */
i = size_a;
while (--i >= 0 && a->ob_digit[i] == b->ob_digit[i])
; //如果都相等,i会变为-1
if (i < 0)
return (PyLongObject *)PyLong_FromLong(0);//a和b相等,直接返回0
if (a->ob_digit[i] < b->ob_digit[i]) {//a的某一位小于b的某一位,依旧要交换
sign = -1;
{ PyLongObject *temp = a; a = b; b = temp; }
}
size_a = size_b = i+1;//最终z的申请的ob_size的大小
}
z = _PyLong_New(size_a);//申请
if (z == NULL)
return NULL;
for (i = 0; i < size_b; ++i) {
borrow = a->ob_digit[i] - b->ob_digit[i] - borrow;
z->ob_digit[i] = borrow & PyLong_MASK;
borrow >>= PyLong_SHIFT;
borrow &= 1; /* Keep only one sign bit */
}
for (; i < size_a; ++i) {
borrow = a->ob_digit[i] - borrow;
z->ob_digit[i] = borrow & PyLong_MASK;
borrow >>= PyLong_SHIFT;
borrow &= 1; /* Keep only one sign bit */
}
assert(borrow == 0);
if (sign < 0) {
Py_SET_SIZE(z, -Py_SIZE(z));
}
return maybe_small_long(long_normalize(z));
}