python 将数组转化8位整数_int对象,永不溢出的整数
點(diǎn)擊上方藍(lán)色小字 “小菜學(xué)編程”?,關(guān)注我們?
整數(shù)溢出
開始介紹 int?對(duì)象前,先考考大家:下面這個(gè)?C?程序( test.c?)運(yùn)行后輸出什么?是 1000000000000?(一萬億)嗎?
#include?int?main(int?argc,?char?*argv[]){
????int?value?=?1000000;
????printf("%d\n",?value?*?value);
????return?0;
}
可能有不少人覺得這沒啥好問的,一百萬乘以一百萬不就是一萬億嗎?但現(xiàn)實(shí)卻不是如此。
在計(jì)算機(jī)中,由于變量類型存儲(chǔ)空間固定,它能表示的數(shù)值范圍也是有限的。以 int?為例,該類型長(zhǎng)度為 32?位,能表示的整數(shù)范圍為 -2147483648?至?2147483647?。一萬億顯然超出該范圍,換句話講程序發(fā)生了 整數(shù)溢出?。因此,運(yùn)行 test.c?,程序這樣輸出也就不奇怪了:
$?gcc?-o?test?test.c$?./test
-727379968
不僅是 C?語言,很多編程語言都存在整數(shù)溢出的問題,數(shù)據(jù)庫中的整數(shù)類型也是。由于整數(shù)溢出現(xiàn)象的存在,程序員需要結(jié)合業(yè)務(wù)場(chǎng)景,謹(jǐn)慎選擇數(shù)據(jù)類型。一旦選擇不慎或者代碼考慮不周,便會(huì)導(dǎo)致嚴(yán)重 BUG?。
int 對(duì)象的行為
與其他語言相比,?Python?中的整數(shù)永遠(yuǎn)不會(huì)有溢出的現(xiàn)象。一百萬乘以一百萬, Python?可以輕易算出來:
>>>?1000000?*?10000001000000000000
Pyhton?甚至可以計(jì)算十的一百次方,這在其他語言是不可想象的:
>>>?10?**?10010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
計(jì)算結(jié)果如此龐大,就算用 64?位整數(shù),也難以表示。但?Python?中的整數(shù)對(duì)象卻可以輕松應(yīng)付,完全不需要任何特殊處理。為什么?Python?整數(shù)有這樣的魔力呢?讓我們深入整數(shù)對(duì)象源碼,撥開心中的迷霧。
在源碼中,我們將領(lǐng)略到?C?語言 實(shí)現(xiàn)大整數(shù)的藝術(shù)?。也許你曾經(jīng)被面試官要求用 C/C++?實(shí)現(xiàn)大整數(shù),卻因?yàn)榭紤]不周而不幸敗北。不要緊,掌握 Python?整數(shù)的設(shè)計(jì)秘密后,實(shí)現(xiàn)大整數(shù)對(duì)你來說將是易如反掌。
int 對(duì)象的設(shè)計(jì)
int?對(duì)象在 Include/longobject.h?頭文件中定義:
typedef?struct?_longobject?PyLongObject;?/*?Revealed?in?longintrepr.h?*/我們順著注釋找到了 Include/longintrepr.h?,實(shí)現(xiàn) int?對(duì)象的結(jié)構(gòu)體真正藏身之處:
struct?_longobject?{????PyObject_VAR_HEAD
????digit?ob_digit[1];
};
這個(gè)結(jié)構(gòu)我們并不陌生,說明 int?對(duì)象是一個(gè)變長(zhǎng)對(duì)象。除了變長(zhǎng)對(duì)象都具有的公共頭部,還有一個(gè) digit?數(shù)組,整數(shù)值應(yīng)該就存儲(chǔ)在這個(gè)數(shù)組里面。digit?又是什么呢?同樣在 Include/longintrepr.h?頭文件,我們找到它的定義:
#if?PYLONG_BITS_IN_DIGIT?==?30typedef?uint32_t?digit;
//?...
#elif?PYLONG_BITS_IN_DIGIT?==?15
typedef?unsigned?short?digit;
//?...
#endif
看上去 digit?就是一個(gè) C?語言整數(shù),至此我們知曉?int?對(duì)象是通過整數(shù)數(shù)組來實(shí)現(xiàn)大整數(shù)的。一個(gè) C?整數(shù)類型不夠就兩個(gè)嘛,兩個(gè)不夠那就 n?個(gè)!至于整數(shù)數(shù)組用什么整數(shù)類型來實(shí)現(xiàn), Python?提供了兩個(gè)版本,一個(gè)是 32?位的 uint32_t ,一個(gè)是 16?位的 unsigned short?,編譯?Python?解析器時(shí)可以通過宏定義指定選用的版本。
這主要是出于內(nèi)存方面的考量:對(duì)于范圍不大的整數(shù),用?16?位整數(shù)表示即可,用 32?位就有點(diǎn)浪費(fèi)。本人卻覺得由于整數(shù)對(duì)象公共頭部已經(jīng)占了 24?字節(jié),省這?2?個(gè)字節(jié)其實(shí)意義不大。
| 16位整數(shù)數(shù)組 | 32位整數(shù)數(shù)組 | |
| 1 | 24 + 2 * 1 = 26 | 24 + 4 * 1 = 28 |
| 1000000 | 24 + 2 * 2 = 28 | 24 + 4 * 1 = 28 |
| 10000000000 | 24 + 2 * 3 = 30 | 24 + 4 * 2 = 32 |
由此可見,選用 16?位整數(shù)數(shù)組時(shí), int?對(duì)象內(nèi)存增長(zhǎng)的粒度更小,有些情況下可以節(jié)省 2?個(gè)字節(jié)。但是這 2?字節(jié)相比 24?字節(jié)的變長(zhǎng)對(duì)象公共頭部顯得微不足道,因此 Python?默認(rèn)選用 32?位整數(shù)數(shù)組也就不奇怪了。
如上圖,對(duì)于比較大的整數(shù), Python 將其拆成若干部分,保存在 ob_digit 數(shù)組中。然而我們注意到在結(jié)構(gòu)體定義中, ob_digit 數(shù)組長(zhǎng)度卻固定為 1 ,這是為什么呢?由于 C 語言中數(shù)組長(zhǎng)度不是類型信息,我們可以根據(jù)實(shí)際需要為 ob_digit 數(shù)組分配足夠的內(nèi)存,并將其當(dāng)成長(zhǎng)度為 n 的數(shù)組操作。這也是 C 語言中一個(gè)常用的編程技巧。
通過上面的學(xué)習(xí),我們知道 int 對(duì)象是通過整數(shù)數(shù)組來實(shí)現(xiàn)大整數(shù)的。那么,大整數(shù)實(shí)現(xiàn)的原理又是如何的呢?
點(diǎn)擊 “
???原創(chuàng)不易,求贊,求在看
總結(jié)
以上是生活随笔為你收集整理的python 将数组转化8位整数_int对象,永不溢出的整数的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: BZOJ3040:最短路——题解
- 下一篇: python仿真智能驾驶_基于Pytho