Skip to content

Commit 962933f

Browse files
committed
close #5
1 parent f189c17 commit 962933f

File tree

3 files changed

+165
-48
lines changed

3 files changed

+165
-48
lines changed

objects/long-object.md

Lines changed: 165 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,107 @@ PyTypeObject PyLong_Type = {
109109
};
110110
```
111111

112+
## 创建整数对象
113+
114+
从 PyLong_Type 可以看出,创建一个整数对象的入口函数为 long_new
115+
116+
`源文件:`[Objects/clinic/longobject.c.h](https://github.com/python/cpython/blob/v3.7.0/Objects/clinic/longobject.c.h#L0)
117+
118+
```c
119+
// Objects/clinic/longobject.c.h
120+
/*[clinic input]
121+
preserve
122+
[clinic start generated code]*/
123+
124+
static PyObject *
125+
long_new_impl(PyTypeObject *type, PyObject *x, PyObject *obase);
126+
127+
static PyObject *
128+
long_new(PyTypeObject *type, PyObject *args, PyObject *kwargs)
129+
{
130+
PyObject *return_value = NULL;
131+
static const char * const _keywords[] = {"", "base", NULL};
132+
static _PyArg_Parser _parser = {"|OO:int", _keywords, 0};
133+
PyObject *x = NULL;
134+
PyObject *obase = NULL;
135+
136+
if (!_PyArg_ParseTupleAndKeywordsFast(args, kwargs, &_parser,
137+
&x, &obase)) {
138+
goto exit;
139+
}
140+
return_value = long_new_impl(type, x, obase);
141+
142+
exit:
143+
return return_value;
144+
}
145+
```
146+
147+
具体实现在 long_new_impl `源文件:`[Objects/longobject.c](https://github.com/python/cpython/blob/v3.7.0/Objects/longobject.c#L4785)
148+
149+
```c
150+
// Objects/longobject.c
151+
152+
/*[clinic input]
153+
@classmethod
154+
int.__new__ as long_new
155+
x: object(c_default="NULL") = 0
156+
/
157+
base as obase: object(c_default="NULL") = 10
158+
[clinic start generated code]*/
159+
160+
static PyObject *
161+
long_new_impl(PyTypeObject *type, PyObject *x, PyObject *obase)
162+
/*[clinic end generated code: output=e47cfe777ab0f24c input=81c98f418af9eb6f]*/
163+
{
164+
Py_ssize_t base;
165+
166+
if (type != &PyLong_Type)
167+
return long_subtype_new(type, x, obase); /* Wimp out */
168+
if (x == NULL) {
169+
if (obase != NULL) {
170+
PyErr_SetString(PyExc_TypeError,
171+
"int() missing string argument");
172+
return NULL;
173+
}
174+
return PyLong_FromLong(0L);
175+
}
176+
if (obase == NULL)
177+
return PyNumber_Long(x);
178+
179+
base = PyNumber_AsSsize_t(obase, NULL);
180+
if (base == -1 && PyErr_Occurred())
181+
return NULL;
182+
if ((base != 0 && base < 2) || base > 36) {
183+
PyErr_SetString(PyExc_ValueError,
184+
"int() base must be >= 2 and <= 36, or 0");
185+
return NULL;
186+
}
187+
188+
if (PyUnicode_Check(x))
189+
return PyLong_FromUnicodeObject(x, (int)base);
190+
else if (PyByteArray_Check(x) || PyBytes_Check(x)) {
191+
char *string;
192+
if (PyByteArray_Check(x))
193+
string = PyByteArray_AS_STRING(x);
194+
else
195+
string = PyBytes_AS_STRING(x);
196+
return _PyLong_FromBytes(string, Py_SIZE(x), (int)base);
197+
}
198+
else {
199+
PyErr_SetString(PyExc_TypeError,
200+
"int() can't convert non-string with explicit base");
201+
return NULL;
202+
}
203+
}
204+
```
205+
206+
从 long_new_impl 函数可以看出有如下几种情况
207+
208+
- x == NULL 且 obase != NULL 调用 PyLong_FromLong
209+
- obase 为NULL 调用 PyNumber_Long
210+
- x 和 obase 都不为 NULL
211+
- PyUnicode 调用PyLong_FromUnicodeObject,最终调用PyLong_FromString
212+
- PyByteArray/PyBytes 调用_PyLong_FromBytes,最终调用PyLong_FromString
112213

113214
## 小整数对象
114215

@@ -293,7 +394,7 @@ print(num)
293394

294395
## 整数对象的数值操作
295396

296-
可以看到整数对象的数值操作较多,由于篇幅限制无法一一分析,这里只分析整数的部分方法
397+
可以看到整数对象的数值操作较多,由于篇幅限制无法一一分析,这里只分析整数的部分操作
297398

298399
`源文件:`[Objects/longobject.c](https://github.com/python/cpython/blob/v3.7.0/Objects/longobject.c#L5341)
299400

@@ -340,13 +441,54 @@ static PyNumberMethods long_as_number = {
340441

341442
### 整数相加
342443

343-
`源文件:`[Objects/longobject.c](https://github.com/python/cpython/blob/v3.7.0/Objects/longobject.c#L2990)
444+
`源文件:`[Objects/longobject.c](https://github.com/python/cpython/blob/v3.7.0/Objects/longobject.c#L3081)
344445

345446
```c
346447
// Objects/longobject.c
347448

348-
/* Add the absolute values of two integers. */
449+
static PyObject *
450+
long_add(PyLongObject *a, PyLongObject *b)
451+
{
452+
PyLongObject *z;
453+
454+
CHECK_BINOP(a, b);
455+
456+
if (Py_ABS(Py_SIZE(a)) <= 1 && Py_ABS(Py_SIZE(b)) <= 1) {
457+
return PyLong_FromLong(MEDIUM_VALUE(a) + MEDIUM_VALUE(b));
458+
}
459+
if (Py_SIZE(a) < 0) {
460+
if (Py_SIZE(b) < 0) {
461+
z = x_add(a, b);
462+
if (z != NULL) {
463+
/* x_add received at least one multiple-digit int,
464+
and thus z must be a multiple-digit int.
465+
That also means z is not an element of
466+
small_ints, so negating it in-place is safe. */
467+
assert(Py_REFCNT(z) == 1);
468+
Py_SIZE(z) = -(Py_SIZE(z));
469+
}
470+
}
471+
else
472+
z = x_sub(b, a);
473+
}
474+
else {
475+
if (Py_SIZE(b) < 0)
476+
z = x_sub(a, b);
477+
else
478+
z = x_add(a, b);
479+
}
480+
return (PyObject *)z;
481+
}
482+
```
483+
484+
可以看到整数的加法运算函数long_add根据 a、b的ob_size 又细分为两个函数 (x_add 和 x_sub) 做处理
485+
486+
`源文件:`[Objects/longobject.c](https://github.com/python/cpython/blob/v3.7.0/Objects/longobject.c#L2991)
487+
488+
```c
489+
// Objects/longobject.c
349490
491+
/* Add the absolute values of two integers. */
350492
static PyLongObject *
351493
x_add(PyLongObject *a, PyLongObject *b)
352494
{
@@ -379,6 +521,17 @@ x_add(PyLongObject *a, PyLongObject *b)
379521
z->ob_digit[i] = carry;
380522
return long_normalize(z);
381523
}
524+
```
525+
526+
加法运算函数 x_add 从 ob_digit 数组的低位开始依次按位相加,carry做进位处理,然后处理a对象的高位数字,最后使用 long_normalize 函数调整 ob_size,确保ob_digit[abs(ob_size)-1]不为零,这与普通四则运算的加法运算相同,只不过进位单元不同而已
527+
528+
![longobject x_add](longobject_x_add.png)
529+
530+
531+
`源文件:`[Objects/longobject.c](https://github.com/python/cpython/blob/v3.7.0/Objects/longobject.c#L3025)
532+
533+
```c
534+
// Objects/longobject.c
382535

383536
/* Subtract the absolute values of two integers. */
384537

@@ -423,7 +576,7 @@ x_sub(PyLongObject *a, PyLongObject *b)
423576
borrow = a->ob_digit[i] - b->ob_digit[i] - borrow;
424577
z->ob_digit[i] = borrow & PyLong_MASK;
425578
borrow >>= PyLong_SHIFT;
426-
borrow &= 1; /* Keep only one sign bit 只保留一位符号位 */
579+
borrow &= 1; /* Keep only one sign bit */
427580
}
428581
for (; i < size_a; ++i) {
429582
borrow = a->ob_digit[i] - borrow;
@@ -437,50 +590,10 @@ x_sub(PyLongObject *a, PyLongObject *b)
437590
}
438591
return long_normalize(z);
439592
}
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-
}
474593
```
475594
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 的过程大致如下图
595+
与普通四则运算减法相同,数不够大则向高一位借位,
596+
减法运算函数 x_sub 的示例图如下,注:PyLong_SHIFT为30
484597
485598
![longobject x_sub](longobject_x_sub.png)
486599
@@ -514,7 +627,11 @@ long_mul(PyLongObject *a, PyLongObject *b)
514627
}
515628
```
516629

517-
k_mul函数 [源文件](
630+
k_mul函数是一种快速乘法 [源文件](
518631
https://github.com/python/cpython/blob/v3.7.0/Objects/longobject.c#L3268)
519632

520-
`k_mul`函数是一种快速乘法[Karatsuba算法](https://www.wikiwand.com/zh-hans/Karatsuba算法)的实现
633+
> Karatsuba的算法主要是用于两个大数的乘法,极大提高了运算效率,相较于普通乘法降低了复杂度,并在其中运用了递归的思想。
634+
> 基本的原理和做法是将位数很多的两个大数x和y分成位数较少的数,每个数都是原来x和y位数的一半。
635+
> 这样处理之后,简化为做三次乘法,并附带少量的加法操作和移位操作。
636+
637+
具体可以看wiki [Karatsuba算法](https://www.wikiwand.com/zh-hans/Karatsuba算法)的实现

objects/longobject_x_add.png

5.32 KB
Loading

objects/longobject_x_sub.png

6.16 KB
Loading

0 commit comments

Comments
 (0)