Cpython3.9源码解析python中的大小整数
作者:菜鸟小超 发布时间:2021-11-17 05:45:42
小整数
/* interpreter state */
#define _PY_NSMALLPOSINTS 257
#define _PY_NSMALLNEGINTS 5
这是CPython
中定义的两个常量,它们用于控制解释器状态中的小整数对象池。在CPython
中,小整数对象池是一种优化机制,用于减少对常用小整数的内存分配和销毁开销。
_PY_NSMALLPOSINTS
定义了正小整数对象池的大小。在这里,其值设置为257,表示解释器将为从0到256(包含0和256)的整数预分配对象并缓存。这些整数在很多场景下会被频繁使用,所以事先创建并缓存它们可以提高性能。
_PY_NSMALLNEGINTS
定义了负小整数对象池的大小。在这里,其值设置为5,表示解释器将为从-1到-5(包含-1和-5)的整数预分配对象并缓存。
在Python解释器启动时,这些小整数对象会被创建并放入对象池。当需要这些整数值时,解释器会直接从对象池中获取对应的对象,而不是动态创建新对象。这样,对于这些小整数值的操作可以更快地进行,节省了内存分配和销毁的开销。
static PyObject *
get_small_int(sdigit ival)
{
assert(IS_SMALL_INT(ival));
PyThreadState *tstate = _PyThreadState_GET();
PyObject *v = (PyObject*)tstate->interp->small_ints[ival + NSMALLNEGINTS];
Py_INCREF(v);
return v;
}
typedef int32_t sdigit; /* signed variant of digit */
#define IS_SMALL_INT(ival) (-NSMALLNEGINTS <= (ival) && (ival) < NSMALLPOSINTS)
这是get_small_int
函数的实现,它用于从小整数对象池中获取一个指定值的小整数对象。小整数对象池包含了一定范围内的整数对象,主要是为了避免对这些常用的整数对象进行频繁的内存分配和销毁。
get_small_int
函数接受一个sdigit
类型的参数ival
,表示要获取的整数值。在函数内部,首先使用assert(IS_SMALL_INT(ival))
确保传入的整数值ival
在小整数对象池的范围内。
接下来,函数获取当前线程状态(PyThreadState
)并从其中获取解释器状态(tstate->interp
)。解释器状态包含了小整数对象池,即small_ints
数组。
然后,根据ival
计算出在small_ints
数组中的索引(ival + NSMALLNEGINTS
),并将对应位置的对象赋值给v
。NSMALLNEGINTS
是一个宏定义,表示负小整数的个数。假设我们有一个整数值 ival
,我们想要在 small_ints
数组中查找这个值对应的预分配的小整数对象。NSMALLNEGINTS
是预分配的负数的数量。在 CPython
中,NSMALLNEGINTS
的值通常为5,表示有5个预分配的负整数对象(-1, -2, -3, -4, -5)。
现在,我们将通过计算 ival + NSMALLNEGINTS
来找到 small_ints
数组中的索引。例如,假设 ival
为3。那么,我们可以计算索引如下:
index = ival + NSMALLNEGINTS
index = 3 + 5
index = 8
这意味着 small_ints
数组中的第8个元素(从0开始计数)是我们要查找的整数对象。在这个例子中,我们将找到预分配的小整数对象3,并将其引用计数加1,然后返回这个对象。
接下来,通过调用Py_INCREF(v)
增加v
的引用计数,以防止对象在其引用计数变为0时被错误地回收。
最后,返回指向小整数对象的指针v
。
总之,get_small_int
函数的作用是从小整数对象池中获取一个指定值的小整数对象,并增加其引用计数,然后返回该对象。这样可以提高对常用小整数的操作性能。
大整数
/* Long integer representation.
The absolute value of a number is equal to
SUM(for i=0 through abs(ob_size)-1) ob_digit[i] * 2**(SHIFT*i)
Negative numbers are represented with ob_size < 0;
zero is represented by ob_size == 0.
In a normalized number, ob_digit[abs(ob_size)-1] (the most significant
digit) is never zero. Also, in all cases, for all valid i,
0 <= ob_digit[i] <= MASK.
The allocation function takes care of allocating extra memory
so that ob_digit[0] ... ob_digit[abs(ob_size)-1] are actually available.
CAUTION: Generic code manipulating subtypes of PyVarObject has to
aware that ints abuse ob_size's sign bit.
*/
这是CPython
源码中关于长整数表示的一段注释。它解释了PyLongObject
如何表示大整数的绝对值和符号。让我们逐行分析这个注释:
1.首先,注释指出大整数的绝对值等于:
SUM(for i=0 through abs(ob_size)-1) ob_digit[i] * 2**(SHIFT*i)
ob_digit
表示长整数的每个“数字”,SHIFT
是每个“数字”的位数,通常为30或15。ob_size
表示长整数的符号和长度,它的绝对值表示长整数的长度,即“数字”的个数。
2.对于负数,ob_size
小于0。对于0,ob_size
等于0。
3.在规范化的数中,最高有效位(即最高“数字”)永远不会为零。此外,在所有情况下,对于所有有效的i,ob_digit[i]
的取值范围在0到MASK
之间。MASK
的值通常为(1 << PyLong_SHIFT) - 1
,即2**PyLong_SHIFT - 1
。
4.注释还提到分配函数负责分配额外的内存,以确保ob_digit[0]
到ob_digit[abs(ob_size)-1]
实际上是可用的。
5.最后,注释中的“警告”部分提醒开发者,操纵PyVarObject
子类型的通用代码需要注意整数会滥用ob_size
的符号位。这是因为ob_size
的符号位同时表示整数的长度和符号,而通常情况下ob_size
仅用于表示长度。
额外解释
ob_digit
是一个表示大整数中每个 “数字” 的数组,它是一个整数数组,用于表示长整数对象(PyLongObject
)中的整数值。每个 “数字” 都有一个固定的位数,由 PyLong_SHIFT
定义(通常为 30 或 15)。例如,假设我们有一个长整数对象,其值为 12345678901234567890。
在这个例子中,假设 PyLong_SHIFT
为 30,这意味着每个 “数字” 可以表示 2^30 = 1073741824 个不同的值。为了将这个大整数表示为 ob_digit
数组,我们需要将整数拆分为基于 2^30 的 “数字”。在这种情况下,我们可以将整数表示为:
12345678901234567890 = 4 * 2^(30*2) + 726238597 * 2^(30*1) + 1026062870 * 2^(30*0)
所以,ob_digit
数组将包含以下元素:
ob_digit[0] = 1026062870
ob_digit[1] = 726238597
ob_digit[2] = 4
在实际的 CPython
源码中,PyLongObject
的定义如下:
typedef struct {
PyObject_VAR_HEAD
digit ob_digit[1];
} PyLongObject;
在这里,ob_digit
是一个长度为1的数组,但实际上,它是一个可变长度数组,根据所需的 “数字” 数量动态分配。要注意的是,当一个 PyLongObject
被创建时,会根据整数值的大小动态分配适当数量的空间来存储 ob_digit
数组。
总之,ob_digit
是一个整数数组,用于表示长整数对象中的大整数值。每个数组元素都是一个 “数字”,具有固定的位数。这种表示方法使得 CPython
能够有效地存储和处理大整数。
来源:https://blog.csdn.net/weixin_41777118/article/details/130174171


猜你喜欢
- docker最近迷恋使用doker容器,在docker容器进行部署MySQL,以前针对容器的安全性一直存在怀疑的态度,不过如果能够通过容器也
- 1.简述:xlrd是读取excel表格数据;支持 xlsx和xls 格式的excel表格;三方模块安装方式:pip3 install xlr
- 可以用两种方式创建MySQL账户:1.使用GRANT语句2.直接操作MySQL授权表最好的方法是使用GRANT语句,因为这样更精确,错误少。
- 导语承载童年的纸飞机你还会叠嘛?如果你是个80后或者90后,那你应该记得小时候玩的纸飞机。叠好后,哈口仙气,飞出去,感觉棒棒哒。虽然是一个极
- 需求描述数据库中 num字段值为:实现的效果:需要将一行数据变成多行实现的sqlSELECT SUBSTRING_INDEX(SUBSTRI
- 本文实例讲述了Python实现PS图像调整颜色梯度效果。分享给大家供大家参考,具体如下:这里用 Python 实现 PS 中的色彩图,可以看
- 我们平日办公时用得最多的软件是Execl、Word或WPS Office等,你的计算机中一定储存着大量的XLS、DOC、WPS文件吧!网页制
- ElementUI在el-table中使用el-popoverVue ElementUI在el-table中使用el-popover,点击嵌
- 描述random() 方法返回随机生成的一个实数,它在[0,1)范围内。import randomhelp(random)FUNCTIONS
- 日志文件一般是按天产生,则通过在程序中判断文件的产生日期与当前时间,更换监控的日志文件程序只是简单的示例一下,监控test1.log 10秒
- 1. 使用默认的session, 在ini文件中:from pyramid.session import UnencryptedCookie
- D:document 文档 浏览器加载的页面 DOM O:object 对象 页面及页面中的任何元素都是对象 M:module 模型 页面中
- 很神奇的一个晚上,居然在以前老同事的群里跟同事讨论起CSS的东西来了,不过很意外的还是有收获。在IE中常常会碰到如果将容器定位后,出现容器内
- SQL语句先前写的时候,很容易把一些特殊的用法忘记,我特此整理了一下SQL语句操作,方便自己写SQL时方便一点,想贴上来,一起看看,同时希望
- 概念关键字:array,数据的组合(多个)存储到一个指定的容器中,用变量指向该容器,然后可以通过变量一次性得到该容器中的所有数据.数组定义语
- 微信小程序获取位置信息的方式有两种,一种是调用微信官方的接口来获取,如getLocation,这种方式只能获取经纬度微信官方文档https:
- 1、首先要配好vs开发工程注意版本;我这使用32位的python那么我vs工程这边也选择32位的编译环境去配置注意点;需要将python安装
- 一、管理数据库连接1、使用配置文件管理连接之约定在数据库上下文类中,如果我们只继承了无参数的DbContext,并且在配置文件中创建了和数据
- 本文介绍了SpringBoot 中使用JSP的方法示例,分享给大家,具体如下:依赖: <parent>
- 一、如何理解本条内容:一个“简单”和“复杂”的例子在我和开发人员沟通一个项目需求的时候,他们频频慨叹Mockup的设计所考虑情况之细致,很多