您好,登錄后才能下訂單哦!
這篇“Cpython3.9源碼分析python中的大小整數”文章的知識點大部分人都不太理解,所以小編給大家總結了以下內容,內容詳細,步驟清晰,具有一定的借鑒價值,希望大家閱讀完這篇文章能有所收獲,下面我們一起來看看這篇“Cpython3.9源碼分析python中的大小整數”文章吧。
/* 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
數組。
以上就是關于“Cpython3.9源碼分析python中的大小整數”這篇文章的內容,相信大家都有了一定的了解,希望小編分享的內容對大家有幫助,若想了解更多相關的知識內容,請關注億速云行業資訊頻道。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。