Skip to content

Commit f189c17

Browse files
committed
新增 整数对象的内容,整数相加与相乘
1 parent 16b0f0c commit f189c17

File tree

1 file changed

+228
-3
lines changed

1 file changed

+228
-3
lines changed

objects/long-object.md

Lines changed: 228 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -43,8 +43,6 @@ typedef struct _longobject PyLongObject; /* Revealed in longintrepr.h */
4343
The allocation function takes care of allocating extra memory
4444
so that ob_digit[0] ... ob_digit[abs(ob_size)-1] are actually available.
4545
46-
内存分配函数要小心额外的内存,
47-
4846
CAUTION: Generic code manipulating subtypes of PyVarObject has to
4947
aware that ints abuse ob_size's sign bit.
5048
@@ -239,7 +237,6 @@ _PyLong_Init(void)
239237
}
240238
```
241239
242-
243240
## 整数的存储结构
244241
245242
`源文件:`[Objects/longobject.c](https://github.com/python/cpython/blob/v3.7.0/Objects/longobject.c#L1581)
@@ -293,3 +290,231 @@ print(num)
293290
![longobject storage](longobject_storage.png)
294291

295292
注:这里的 30 是由 **PyLong_SHIFT** 决定的,64位系统中,**PyLong_SHIFT** 为30,否则 **PyLong_SHIFT** 为15
293+
294+
## 整数对象的数值操作
295+
296+
可以看到整数对象的数值操作较多,由于篇幅限制无法一一分析,这里只分析整数的部分方法
297+
298+
`源文件:`[Objects/longobject.c](https://github.com/python/cpython/blob/v3.7.0/Objects/longobject.c#L5341)
299+
300+
```c
301+
// Objects/longobject.c
302+
303+
static PyNumberMethods long_as_number = {
304+
(binaryfunc)long_add, /*nb_add 加法 */
305+
(binaryfunc)long_sub, /*nb_subtract 减法 */
306+
(binaryfunc)long_mul, /*nb_multiply 乘法 */
307+
long_mod, /*nb_remainder 取余 */
308+
long_divmod, /*nb_divmod */
309+
long_pow, /*nb_power 求幂 */
310+
(unaryfunc)long_neg, /*nb_negative */
311+
(unaryfunc)long_long, /*tp_positive */
312+
(unaryfunc)long_abs, /*tp_absolute 绝对值 */
313+
(inquiry)long_bool, /*tp_bool 求bool值 */
314+
(unaryfunc)long_invert, /*nb_invert 反转 */
315+
long_lshift, /*nb_lshift 逻辑左移 */
316+
(binaryfunc)long_rshift, /*nb_rshift 逻辑右移 */
317+
long_and, /*nb_and 与操作 */
318+
long_xor, /*nb_xor 异或 */
319+
long_or, /*nb_or 或操作 */
320+
long_long, /*nb_int*/
321+
0, /*nb_reserved*/
322+
long_float, /*nb_float*/
323+
0, /* nb_inplace_add */
324+
0, /* nb_inplace_subtract */
325+
0, /* nb_inplace_multiply */
326+
0, /* nb_inplace_remainder */
327+
0, /* nb_inplace_power */
328+
0, /* nb_inplace_lshift */
329+
0, /* nb_inplace_rshift */
330+
0, /* nb_inplace_and */
331+
0, /* nb_inplace_xor */
332+
0, /* nb_inplace_or */
333+
long_div, /* nb_floor_divide */
334+
long_true_divide, /* nb_true_divide */
335+
0, /* nb_inplace_floor_divide */
336+
0, /* nb_inplace_true_divide */
337+
long_long, /* nb_index */
338+
};
339+
```
340+
341+
### 整数相加
342+
343+
`源文件:`[Objects/longobject.c](https://github.com/python/cpython/blob/v3.7.0/Objects/longobject.c#L2990)
344+
345+
```c
346+
// Objects/longobject.c
347+
348+
/* Add the absolute values of two integers. */
349+
350+
static PyLongObject *
351+
x_add(PyLongObject *a, PyLongObject *b)
352+
{
353+
Py_ssize_t size_a = Py_ABS(Py_SIZE(a)), size_b = Py_ABS(Py_SIZE(b));
354+
PyLongObject *z;
355+
Py_ssize_t i;
356+
digit carry = 0;
357+
358+
/* Ensure a is the larger of the two: */
359+
// 确保 a 大于 b
360+
if (size_a < size_b) {
361+
{ PyLongObject *temp = a; a = b; b = temp; }
362+
{ Py_ssize_t size_temp = size_a;
363+
size_a = size_b;
364+
size_b = size_temp; }
365+
}
366+
z = _PyLong_New(size_a+1);
367+
if (z == NULL)
368+
return NULL;
369+
for (i = 0; i < size_b; ++i) {
370+
carry += a->ob_digit[i] + b->ob_digit[i];
371+
z->ob_digit[i] = carry & PyLong_MASK;
372+
carry >>= PyLong_SHIFT;
373+
}
374+
for (; i < size_a; ++i) {
375+
carry += a->ob_digit[i];
376+
z->ob_digit[i] = carry & PyLong_MASK;
377+
carry >>= PyLong_SHIFT;
378+
}
379+
z->ob_digit[i] = carry;
380+
return long_normalize(z);
381+
}
382+
383+
/* Subtract the absolute values of two integers. */
384+
385+
static PyLongObject *
386+
x_sub(PyLongObject *a, PyLongObject *b)
387+
{
388+
Py_ssize_t size_a = Py_ABS(Py_SIZE(a)), size_b = Py_ABS(Py_SIZE(b));
389+
PyLongObject *z;
390+
Py_ssize_t i;
391+
int sign = 1;
392+
digit borrow = 0;
393+
394+
/* Ensure a is the larger of the two: */
395+
// 确保 a 大于 b
396+
if (size_a < size_b) {
397+
sign = -1;
398+
{ PyLongObject *temp = a; a = b; b = temp; }
399+
{ Py_ssize_t size_temp = size_a;
400+
size_a = size_b;
401+
size_b = size_temp; }
402+
}
403+
else if (size_a == size_b) {
404+
/* Find highest digit where a and b differ: */
405+
// 找到最高位 a 与 b的差异
406+
i = size_a;
407+
while (--i >= 0 && a->ob_digit[i] == b->ob_digit[i])
408+
;
409+
if (i < 0)
410+
return (PyLongObject *)PyLong_FromLong(0);
411+
if (a->ob_digit[i] < b->ob_digit[i]) {
412+
sign = -1;
413+
{ PyLongObject *temp = a; a = b; b = temp; }
414+
}
415+
size_a = size_b = i+1;
416+
}
417+
z = _PyLong_New(size_a);
418+
if (z == NULL)
419+
return NULL;
420+
for (i = 0; i < size_b; ++i) {
421+
/* The following assumes unsigned arithmetic
422+
works module 2**N for some N>PyLong_SHIFT. */
423+
borrow = a->ob_digit[i] - b->ob_digit[i] - borrow;
424+
z->ob_digit[i] = borrow & PyLong_MASK;
425+
borrow >>= PyLong_SHIFT;
426+
borrow &= 1; /* Keep only one sign bit 只保留一位符号位 */
427+
}
428+
for (; i < size_a; ++i) {
429+
borrow = a->ob_digit[i] - borrow;
430+
z->ob_digit[i] = borrow & PyLong_MASK;
431+
borrow >>= PyLong_SHIFT;
432+
borrow &= 1; /* Keep only one sign bit */
433+
}
434+
assert(borrow == 0);
435+
if (sign < 0) {
436+
Py_SIZE(z) = -Py_SIZE(z);
437+
}
438+
return long_normalize(z);
439+
}
440+
441+
static PyObject *
442+
long_add(PyLongObject *a, PyLongObject *b)
443+
{
444+
PyLongObject *z;
445+
446+
CHECK_BINOP(a, b);
447+
448+
if (Py_ABS(Py_SIZE(a)) <= 1 && Py_ABS(Py_SIZE(b)) <= 1) {
449+
return PyLong_FromLong(MEDIUM_VALUE(a) + MEDIUM_VALUE(b));
450+
}
451+
if (Py_SIZE(a) < 0) {
452+
if (Py_SIZE(b) < 0) {
453+
z = x_add(a, b);
454+
if (z != NULL) {
455+
/* x_add received at least one multiple-digit int,
456+
and thus z must be a multiple-digit int.
457+
That also means z is not an element of
458+
small_ints, so negating it in-place is safe. */
459+
assert(Py_REFCNT(z) == 1);
460+
Py_SIZE(z) = -(Py_SIZE(z));
461+
}
462+
}
463+
else
464+
z = x_sub(b, a);
465+
}
466+
else {
467+
if (Py_SIZE(b) < 0)
468+
z = x_sub(a, b);
469+
else
470+
z = x_add(a, b);
471+
}
472+
return (PyObject *)z;
473+
}
474+
```
475+
476+
可以看到整数的加法运算函数long_add根据 a、b的ob_size 又细分为两个函数做处理 x_add 和 x_sub
477+
478+
加法运算函数 x_add 从 ob_digit 数组的低位开始依次按位相加,carry做进位处理,
479+
然后做处理a对象的高位数字,最后使用 long_normalize 函数调整 ob_size,确保ob_digit[abs(ob_size)-1]不为零,其过程大致如下图
480+
481+
![longobject x_add](longobject_x_add.png)
482+
483+
减法运算函数 x_sub 的过程大致如下图
484+
485+
![longobject x_sub](longobject_x_sub.png)
486+
487+
### 整数相乘
488+
489+
`源文件:`[Objects/longobject.c](https://github.com/python/cpython/blob/v3.7.0/Objects/longobject.c#L3547)
490+
491+
```c
492+
// Objects/longobject.c
493+
static PyObject *
494+
long_mul(PyLongObject *a, PyLongObject *b)
495+
{
496+
PyLongObject *z;
497+
498+
CHECK_BINOP(a, b);
499+
500+
/* fast path for single-digit multiplication */
501+
if (Py_ABS(Py_SIZE(a)) <= 1 && Py_ABS(Py_SIZE(b)) <= 1) {
502+
stwodigits v = (stwodigits)(MEDIUM_VALUE(a)) * MEDIUM_VALUE(b);
503+
return PyLong_FromLongLong((long long)v);
504+
}
505+
506+
z = k_mul(a, b);
507+
/* Negate if exactly one of the inputs is negative. */
508+
if (((Py_SIZE(a) ^ Py_SIZE(b)) < 0) && z) {
509+
_PyLong_Negate(&z);
510+
if (z == NULL)
511+
return NULL;
512+
}
513+
return (PyObject *)z;
514+
}
515+
```
516+
517+
k_mul函数 [源文件](
518+
https://github.com/python/cpython/blob/v3.7.0/Objects/longobject.c#L3268)
519+
520+
`k_mul`函数是一种快速乘法[Karatsuba算法](https://www.wikiwand.com/zh-hans/Karatsuba算法)的实现

0 commit comments

Comments
 (0)