2014-04-27 41 views
2

所以我一直創造numpy的陣列那樣:當我爲給定的dtype設置的值太大時會發生什麼?

>>> u = np.zeros(10, int) 
>>> v = np.zeros(10, float) 

我一直無視有關最大允許值,直到如今。我一直認爲它會簡單地工作。如果沒有,我會得到OverflowError,然後我會找到一些解決方法,如採取對數。

但最近我開始使用其他dtypes:

>>> v8 = np.zeros(10, np.uint8) 
>>> v8[0] = 2 ** 8 - 1 
>>> v8[1] = 2 ** 8 
>>> v8 
>>> array([255, 0, 0, 0, 0, 0, 0, 0, 0, 0], dtype=uint8) 

好了,所以當我分配比255這是一個有點嚇人更大的價值我沒有得到任何警告。

所以我的問題是:

  • 當我使用類型intfloat陣列,是有可能,我設置的值過大(導致完全錯誤的計算)不知道呢?
  • 如果我想使用uint8,我必須手動檢查所有分配的值是否在[ 0, 255 ]

回答

0

是,UINT8會掩蓋你的價值觀(帶8 LSB),所以你需要手動檢查:

>>> a = numpy.uint8(256) 
>>> a 
0 

是的,你沒有意識到它可能會發生溢出。這是許多編程語言的常見錯誤來源。但是,python中的長整型以不同尋常的方式運行:它們沒有明確定義的限制。

我已經在this answer中寫過。

1

numpy在機器層面非常深入。測試很耗時,所以測試由開發人員完成。 Python更高級並且許多測試都是自動完成的,或者對於int,int可以具有任意大的值。無處不在你需要在速度和安全之間做出決定。在速度方面,numpy更遠。

在需要測試值範圍的情況下,您必須自行檢查。

- 方法可以幫助你:

>>> u = np.array([124,-130, 213]) 
>>> u.astype('b') 
array([124, 126, -43], dtype=int8) 
>>> u.clip(-128,127).astype('b') 
array([ 124, -128, 127], dtype=int8) 
1

正如在其他的答案解釋,過大型值「纏」,所以你需要手工剪裁他們的最小值和最大值轉換前允許的值。對於整數,這些限制可以使用np.iinfo獲得。你可以寫你自己的效用函數做這個轉換以安全的方式對一個給定的D型:

def safe_convert(x, new_dtype): 
    info = np.iinfo(new_dtype) 
    return x.clip(info.min, info.max).astype(new_dtype) 

快速測試:

In [31]: safe_convert(np.array([-1,0,1,254,255,256]), np.uint8) 
Out[31]: array([ 0, 0, 1, 254, 255, 255], dtype=uint8) 

In [32]: safe_convert(np.array([-129,-128,-127,126,127,128]), np.int8) 
Out[32]: array([-128, -128, -127, 126, 127, 127], dtype=int8) 
0

如前所述,numpy的環繞避免做檢查。

如果裁剪不可接受,那麼在投射之前,您可以使用numpy.min_scalar_type來獲取將保留數據而不丟失數據的最小dtype。

另外請注意,實際上使用uint8的唯一理由是將存儲器保存在非常大的陣列中,因爲計算速度通常大致相同(在某些操作中將內部向上流動,甚至是向上流動)。如果你的陣列不是太大以至於內存不是一個大問題,你應該更安全,並且使用uint16甚至uint32來進行中間計算。如果內存是你的問題,你應該考慮移出核心存儲,比如PyTables;如果您現在即將填滿內存,也許使用更大的數據集即使uint8也不足夠。

相關問題