python基础-数据结构-int类型——你知道python的最大整数是什么吗?无限大?还是sys.maxsize?

文章目录

int底层源码

pythonint类型貌似并没有一个位数上线,然而我们知道其他语言的整数都是有位数,一般为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 位存储符号信息:
      • 0: 正数
      • 1: 零
      • 2: 负数
    • 第三低位(当前未使用)保留用于"immortality flag"(不死标志)。
  • 数字的个数(ndigits)存储在 lv_tag 的高位部分。

因此python中的int的长度是根据其lv_tag所能表示Number of digits(数字的个数)来决定的,由于uintptr_t32位与64位操作系统所表示的整数是不同的因此,python的位数也是不同的

c 复制代码
#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 的值定义了不同大小的 digittwodigits 类型,并定义了一些与长整数表示相关的常量。
  • PyLong_SHIFT 定义了每个 digit 的位数。
  • _PyLong_DECIMAL_SHIFT_PyLong_DECIMAL_BASE 定义了十进制表示中的一些常量。

最大整数推断

假设 lv_tag 为一个 64 位的 uintptr_t,并且 PYLONG_BITS_IN_DIGIT 为 30:

c 复制代码
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 位,可以得到长整数的符号。
  • 数值的绝对值计算公式:
    absolute value = ∑ i = 0 ndigits − 1 ob_digit [ i ] × 2 PyLong_SHIFT × i \text{absolute value} = \sum_{i=0}^{\text{ndigits}-1} \text{ob\_digit}[i] \times 2^{\text{PyLong\_SHIFT} \times i} absolute value=i=0∑ndigits−1ob_digit[i]×2PyLong_SHIFT×i
    那我们可以从中推断python所能表示的最大整数,
  • 首先我们假设PyLong_SHIFTPYLONG_BITS_IN_DIGIT30
  • 因此我们可以计算出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的符号位并不影响存储数字的大小以及个数,所以其最小整数的绝对值与最大正数的绝对值相同

相关推荐
奔跑吧邓邓子5 分钟前
【Python爬虫(44)】分布式爬虫:筑牢安全防线,守护数据之旅
开发语言·分布式·爬虫·python·安全
小王努力学编程5 分钟前
【算法与数据结构】单调队列
数据结构·c++·学习·算法·leetcode
C#Thread21 分钟前
C#上位机--流程控制(IF语句)
开发语言·javascript·ecmascript
程序员 小濠30 分钟前
接口测试基础 --- 什么是接口测试及其测试流程?
自动化测试·python·测试工具·职场和发展·appium·接口测试·压力测试
程序媛徐师姐38 分钟前
Python基于Django的酒店推荐系统【附源码】
python·django·酒店·酒店推荐·python django·酒店推荐系统·python酒店推荐系统
万兴丶1 小时前
Unity 适用于单机游戏的红点系统(前缀树 | 数据结构 | 设计模式 | 算法 | 含源码)
数据结构·unity·设计模式·c#
牵牛老人1 小时前
Qt开发中出现中文乱码问题深度解析与解决方案
开发语言·qt
大脑经常闹风暴@小猿1 小时前
1.1 go环境搭建及基本使用
开发语言·后端·golang
程序员东min1 小时前
数据结构:实验题目:单链表归并。将两个非递减次序排列的单链表归并为一个非递增次序排列的单链表,并计算表长。要求利用原来两个单链表的结点存放合并后的单链表。
数据结构
~kiss~1 小时前
python的thrift2pyi学习
windows·python·学习