某位 A 同窗發了我一張截圖,問爲什麼結果中出現了負數?html
看了圖,我第一感受就是數據溢出了。數據超出能表示的最大值,就會出現奇奇怪怪的結果。python
而後,他繼續發了張圖,內容是 print(100000*208378),就是直接打印上圖的 E[0]*G[0],結果是 20837800000,這是個正確的結果。程序員
因此新的問題是:若是說上圖的數據溢出了,爲什麼直接相乘的數卻沒有溢出?編程
因爲我一直忽視數據的表示規則(整型的上限是多少?),並且對 Numpy 瞭解很少,還錯看了圖中結果,誤覺得每個數據都是錯誤的,因此就解答不出來。函數
最後,通過學習羣裏的一番討論,我才終於明白是怎麼回事,因此本文把相關知識點作個梳理。學習
在正式開始以前,先總結一下上圖會引出的話題:翻譯
關於第一個問題,先看看 Python 2,它有兩種整數:3d
sys.maxint()
查看(取決於平臺是 32 位仍是 64 位)當一個整數超出短整數範圍時,它會自動採用長整數表示。舉例,打印 2**100
,結果會在末尾加字母 L 表示它是長整數。code
可是到了 Python 3,狀況就不一樣了:它僅有一種內置的整數,表示爲 int,形式上是 Python 2 的短整數,但實際上它能表示的範圍無限,行爲上更像是長整數。不管多大的數,結尾都不須要字母 L 來做區分。htm
也就是說,Python 3 整合了兩種整數表示法,用戶再也不須要自行區分,全交給底層按需處理。
理論上,Python 3 中的整數沒有上限(只要不超出內存空間)。這就解釋了前文中直接打印兩數相乘,爲何結果會正確了。
PEP-237(Unifying Long Integers and Integers)中對這個轉變做了說明。它解釋這樣作的 目的:
> 這會給新的 Python 程序員(不管他們是不是編程新手)減小一項上手前要學的功課。
Python 在語言運用層屏蔽了不少瑣碎的活,好比內存分配,因此,咱們在使用字符串、列表或字典等對象時,根本不用操心。整數類型的轉變,也是出於這樣的便利目的。(壞處是犧牲了一些效率,在此就不談了)
回到前面的第二個話題:Numpy 中整數的上限是多少?
因爲它是 C 語言實現,在整數表示上,用的是 C 語言的規則,也就是會區分整數和長整數。
有一種方式可查看:
import numpy as np a = np.arange(2) type(a[0]) # 結果:numpy.int32
也就是說它默認的整數 int 是 32 位,表示範圍在 -2147483648 ~ 2147483647。
對照前文的截圖,裏面只有兩組數字相乘時沒有溢出:100007*454九、100012*13264,其它數據組都溢出了,因此出現奇怪的負數結果。
Numpy 支持的數據類型要比 Python 的多,相互間的區分界限不少樣:
截圖來源:https://www.runoob.com/numpy/numpy-dtype.html
要解決整數溢出問題,能夠經過指定 dtype 的方式:
import numpy as np q = [100000] w = [500000] # 一個溢出的例子: a = np.array(q) b = np.array(w) print(a*b) # 產生溢出,結果是個奇怪的數值 # 一個解決的例子: c = np.array(q, dtype='int64') d = np.array(w, dtype='int64') print(c*d) # 沒有溢出:[50000000000]
好了,前面提出的問題就回答完了。來做個結尾吧:
公衆號【Python貓】, 本號連載優質的系列文章,有喵星哲學貓系列、Python進階系列、好書推薦系列、技術寫做、優質英文推薦與翻譯等等,歡迎關注哦。