本节主要目的要基本了解python中整数加减运算的实现,在此之前要先了解python中整数实现方式可以先查看(一)之后再看本节。
注:这里说明一下,下面介绍均已8个比特位举例。那么ob_digit 每一个元素我们认定最多只能占7位。从源码中类推过来,这样是为了防止两数相加溢出问题,比如255+255 这时8位肯定放不下了,只占7位最多127+127=254。
1.加法运算在了解了整数实现之后,我们在同一文件下(longobject.c)可以发现long_add函数实现了两整数相加的运算,那么接下来我们就来一步一步分析其实现:
static PyObject *
long_add(PyLongObject *a, PyLongObject *b)
{
PyLongObject *z;
CHECK_BINOP(a, b);
if (Py_ABS(Py_SIZE(a)) <= 1 && Py_ABS(Py_SIZE(b)) <= 1) {
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) {
assert(Py_REFCNT(z) == 1);
Py_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;
}
从上面这段代码中首先可以看到当整数ob_digit长度<=1的时候是通过PyLong_FromLong(MEDIUM_VALUE(a) + MEDIUM_VALUE(b))来求值的,那么接下来就简单看一下它的实现方式:
先将a,b的值通过C相加之后再由 PyLong_FromLong转成Python的整数对象,那么接下来我们就先看一下它是如何转换的。
PyObject *
PyLong_FromLong(long ival)
{
PyLongObject *v;
unsigned long abs_ival;
unsigned long t;
int ndigits = 0;
int sign;
CHECK_SMALL_INT(ival);
if (ival < 0) {
abs_ival = 0U-(unsigned long)ival;
sign = -1;
}
else {
abs_ival = (unsigned long)ival;
sign = ival == 0 ? 0 : 1;
}
if (!(abs_ival >> PyLong_SHIFT)) {
v = _PyLong_New(1);
if (v) {
Py_SIZE(v) = sign;
v->ob_digit[0] = Py_SAFE_DOWNCAST(
abs_ival, unsigned long, digit);
}
return (PyObject*)v;
}
t = abs_ival;
while (t) {
++ndigits;
t >>= PyLong_SHIFT;
}
// 此处ndigits = 2
v = _PyLong_New(ndigits);
if (v != NULL) {
digit *p = v->ob_digit;
Py_SIZE(v) = ndigits*sign; // 此处v的ob_size=2
t = abs_ival; //t重新赋值200
while (t) {
// 第一次 t & PyLong_MASK = 200 & 127 = 0100 1000 = 72
// 第二次 t & PyLong_MASK = 1 & 127 = 0000 0001 = 1
*p++ = Py_SAFE_DOWNCAST(
t & PyLong_MASK, unsigned long, digit);
t >>= PyLong_SHIFT;
}
}
return (PyObject *)v;
}
通过上述介绍,我们应该可以清楚ob_size的绝对值小于等于1的Python整数是如何相加的。
那么接下来看其他情况:根据两个数正负来判断是执行x_add函数还是执行x_sub函数,我们均已举例说明的方式查看。
例1:a = -200, b = -600
解析:此时当执行x_add函数
分别将a,b转为python对象
a = {ob_size: 2, ob_digit: [72, 1]}
b = {ob_size: 2, ob_digit: [88, 4]}
static PyLongObject *
x_add(PyLongObject *a, PyLongObject *b)
{
// size_a = size_b = 2
Py_ssize_t size_a = Py_ABS(Py_SIZE(a)), size_b = Py_ABS(Py_SIZE(b));
PyLongObject *z;
Py_ssize_t i;
digit carry = 0;
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; // z->ob_digit[2] = 0
return long_normalize(z);
}
最终结果:z = {ob_size: -2, ob_digit: [32, 6]} = -(32*128**0 + 6*128**1) = -800
例2:a = 200, b = -600
解析:此时执行x_sub(a, b)
将a,b分别转成python对象
a = {ob_size: 2, ob_digit: [72, 1]}
b = {ob_size: -2, ob_digit: [88, 4]}
将a和b带入x_sub
static PyLongObject *
x_sub(PyLongObject *a, PyLongObject *b)
{
// size_a = size_b = 2
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;
digit borrow = 0;
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) {
i = size_a;
while (--i >= 0 && a->ob_digit[i] == b->ob_digit[i])
;
if (i < 0)
return (PyLongObject *)PyLong_FromLong(0);
if (a->ob_digit[i] < b->ob_digit[i]) {
sign = -1; // 标志结果为负数
{ PyLongObject *temp = a; a = b; b = temp; }
}
size_a = size_b = i+1;
}
// 执行至此,a和b已交换
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;
}
for (; i < size_a; ++i) {
borrow = a->ob_digit[i] - borrow;
z->ob_digit[i] = borrow & PyLong_MASK;
borrow >>= PyLong_SHIFT;
borrow &= 1;
}
assert(borrow == 0);
if (sign < 0) { // 本例此时成立
Py_SIZE(z) = -Py_SIZE(z);
}
return long_normalize(z);
}
最终结果:z = {ob_size: -2, ob_digit: [16, 3]} = -(16*128**0 + 3*128**1) = -400
2.减法运算
减法运算原理其实跟加法差不多的,就不在赘述了。



