赞
踩
python
的int
类型貌似并没有一个位数上线,然而我们知道其他语言的整数都是有位数,一般为32
位或者64
位等,那么python
是怎么实现int
类型没有位数限制的呢,下面这段代码是cpython
仓库中实现python int
的代码,int被定义为_longobject
的结构体,它的数字部分是一个_PyLongValue
的结构体,_PyLongValue
结构体有两个属性:
ob_digit
是一个无符号整型的数组初始化长度为1,后续长度会动态改变,用于存储数字ob_digit
中的每一个长整数由多个 30 位或 15 位的 digit
组成,具体取决于平台。lv_tag
被用于存储int数据的数字个数、符号和标志lv_tag
的位分配:
ndigits = lv_tag >> _PyLong_NON_SIZE_BITS
)存储的是长整数中的“数字”个数(ndigits
)。2
位存储符号信息:
ndigits
)存储在 lv_tag
的高位部分。因此python
中的int的长度是根据其lv_tag
所能表示Number of digits
(数字的个数)来决定的,由于uintptr_t
在32
位与64
位操作系统所表示的整数是不同的因此,python
的位数也是不同的
#if PYLONG_BITS_IN_DIGIT == 30 typedef uint32_t digit; // 指定了每个数字的类型 typedef int32_t sdigit; typedef uint64_t twodigits; typedef int64_t stwodigits; #define PyLong_SHIFT 30 #define _PyLong_DECIMAL_SHIFT 9 #define _PyLong_DECIMAL_BASE ((digit)1000000000) #elif PYLONG_BITS_IN_DIGIT == 15 typedef unsigned short digit; // 指定了每个数字的类型 typedef short sdigit; typedef unsigned long twodigits; typedef long stwodigits; #define PyLong_SHIFT 15 #define _PyLong_DECIMAL_SHIFT 4 #define _PyLong_DECIMAL_BASE ((digit)10000) #else #error "PYLONG_BITS_IN_DIGIT should be 15 or 30" #endif /******************上面的代码主要是根据不同的平台定义整数中每个元素的位数*************************/ #define PyLong_BASE ((digit)1 << PyLong_SHIFT) #define PyLong_MASK ((digit)(PyLong_BASE - 1)) #define PyObject_HEAD PyObject ob_base; #define _PyLong_SIGN_MASK 3 // 用于获得符号位 #define _PyLong_NON_SIZE_BITS 3 // 用于获得ob_digit元素的个数 typedef struct _PyLongValue { uintptr_t lv_tag; /* Number of digits, sign and flags */ digit ob_digit[1]; } _PyLongValue; struct _longobject { PyObject_HEAD _PyLongValue long_value; };
PYLONG_BITS_IN_DIGIT
的值定义了不同大小的 digit
和 twodigits
类型,并定义了一些与长整数表示相关的常量。PyLong_SHIFT
定义了每个 digit
的位数。_PyLong_DECIMAL_SHIFT
和 _PyLong_DECIMAL_BASE
定义了十进制表示中的一些常量。假设 lv_tag
为一个 64 位的 uintptr_t
,并且 PYLONG_BITS_IN_DIGIT
为 30:
uintptr_t lv_tag = ...; // 假设这个值已经被设置
int num_digits = lv_tag >> _PyLong_NON_SIZE_BITS; // 提取数字的个数
int sign = lv_tag & _PyLong_SIGN_MASK; // 提取符号
lv_tag >> _PyLong_NON_SIZE_BITS
提取 lv_tag
的高位部分,可以得到长整数中的数字个数(ndigits
)。lv_tag & _PyLong_SIGN_MASK
提取 lv_tag
的低 2 位,可以得到长整数的符号。PyLong_SHIFT
和PYLONG_BITS_IN_DIGIT
是30
,ob_digit
中每个元素的最大值为 MAX_DIGIT = (1 << PYLONG_SHIFT) - 1= 2^30 - 1 = 1073741823
lv_tag
是一个64位的无符号整数,其最低3
为符号标志,那么前61
位是所能表示的整数的个数num_digits
最大值NUM_DIGITS = (1 << 61) - 1 = 2305843009213693951
python
所能表示的最大整数是
∑
i
=
0
num_digits
−
1
(
2
30
−
1
)
×
2
30
i
=
(
2
30
)
2
61
−
1
−
1
\sum_{i=0}^{\text{num\_digits}-1} (2^{30} - 1) \times 2^{30i} = (2^{30})^{2^{61} - 1} - 1
∑i=0num_digits−1(230−1)×230i=(230)261−1−1,这个数字大到已经远超内存限制对于一个由
num_digits
个 30 位digit
组成的最大整数,其值表示为:max_int = ∑ i = 0 num_digits − 1 ( 2 30 − 1 ) × 2 30 i \text{max\_int} = \sum_{i=0}^{\text{num\_digits}-1} (2^{30} - 1) \times 2^{30i} max_int=∑i=0num_digits−1(230−1)×230i
我们可以将这个求和公式拆开来看: max_int = ( 2 30 − 1 ) × ( 1 + 2 30 + 2 60 + … + 2 30 ( num_digits − 1 ) ) \text{max\_int} = (2^{30} - 1) \times (1 + 2^{30} + 2^{60} + \ldots + 2^{30(\text{num\_digits} - 1)}) max_int=(230−1)×(1+230+260+…+230(num_digits−1))
注意到括号内的部分是一个几何级数,其公比为 2 30 2^{30} 230,项数为num_digits
。对于一个等比数列 1 + r + r 2 + … + r n − 1 1 + r + r^2 + \ldots + r^{n-1} 1+r+r2+…+rn−1,它的和为: S = r n − 1 r − 1 S = \frac{r^n - 1}{r- 1} S=r−1rn−1
在这里, r = 2 30 r = 2^{30} r=230,而项数 n = num_digits n = \text{num\_digits} n=num_digits。
所以: 1 + 2 30 + 2 60 + … + 2 30 ( num_digits − 1 ) = ( 2 30 ) num_digits − 1 2 30 − 1 1 + 2^{30} + 2^{60} + \ldots + 2^{30(\text{num\_digits} - 1)} = \frac{(2^{30})^{\text{num\_digits}} - 1}{2^{30} - 1} 1+230+260+…+230(num_digits−1)=230−1(230)num_digits−1
将这个结果代入最大整数公式中,我们得到: max_int = ( 2 30 − 1 ) × ( 2 30 ) num_digits − 1 2 30 − 1 \text{max\_int} = (2^{30} - 1) \times \frac{(2^{30})^{\text{num\_digits}} - 1}{2^{30} - 1} max_int=(230−1)×230−1(230)num_digits−1可以简化为: max_int = ( 2 30 ) num_digits − 1 \text{max\_int} = (2^{30})^{\text{num\_digits}} - 1 max_int=(230)num_digits−1
num_digits
的最大值为: num_digits = 2 61 − 1 \text{num\_digits} = 2^{61} - 1 num_digits=261−1将这个值代入最大整数公式中,我们得到: max_int = ( 2 30 ) 2 61 − 1 − 1 \text{max\_int} = (2^{30})^{2^{61} - 1} - 1 max_int=(230)261−1−1
因为python的符号位并不影响存储数字的大小以及个数,所以其最小整数的绝对值与最大正数的绝对值相同
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。