NumPy 核心數學函式庫#
numpy 核心數學函式庫 (npymath
) 是朝著這個方向邁出的第一步。這個函式庫包含大多數與數學相關的 C99 功能,這些功能可以在不完全支援 C99 的平台上使用。核心數學函數具有與 C99 函數相同的 API,除了 npy_*
前綴。
可用的函數定義在 <numpy/npy_math.h>
中 - 如有疑問,請參考此標頭檔。
注意
目前正在努力使 npymath
更小(因為編譯器對 C99 的相容性隨著時間的推移而提高),並且更容易銷售或用作僅標頭檔的依賴項。這將避免運送靜態函式庫時,其編譯器可能與下游套件或終端使用者使用的編譯器不符的問題。詳情請參閱 gh-20880。
浮點數分類#
-
NPY_NAN#
此巨集定義為 NaN(非數字),並保證符號位未設定(「正」NaN)。對應的單精度和延伸精度巨集可使用後綴 F 和 L。
-
NPY_INFINITY#
此巨集定義為正 inf。對應的單精度和延伸精度巨集可使用後綴 F 和 L。
-
NPY_PZERO#
此巨集定義為正零。對應的單精度和延伸精度巨集可使用後綴 F 和 L。
-
NPY_NZERO#
此巨集定義為負零(即符號位已設定)。對應的單精度和延伸精度巨集可使用後綴 F 和 L。
-
npy_isnan(x)#
這是 C99 isnan 的別名:適用於單精度、雙精度和延伸精度,如果 x 是 NaN,則傳回非 0 值。
-
npy_isfinite(x)#
這是 C99 isfinite 的別名:適用於單精度、雙精度和延伸精度,如果 x 既不是 NaN 也不是無限大,則傳回非 0 值。
-
npy_isinf(x)#
這是 C99 isinf 的別名:適用於單精度、雙精度和延伸精度,如果 x 是無限大(正和負),則傳回非 0 值。
-
npy_signbit(x)#
這是 C99 signbit 的別名:適用於單精度、雙精度和延伸精度,如果 x 的符號位已設定(即數字為負數),則傳回非 0 值。
-
npy_copysign(x, y)#
這是 C99 copysign 的別名:傳回 x,其符號與 y 相同。適用於任何值,包括 inf 和 nan。單精度和延伸精度可使用後綴 f 和 l。
有用的數學常數#
以下數學常數可在 npy_math.h
中取得。單精度和延伸精度也可透過分別新增 f
和 l
後綴來取得。
-
NPY_E#
自然對數的底 (\(e\))
-
NPY_LOG2E#
歐拉常數的以 2 為底的對數 (\(\frac{\ln(e)}{\ln(2)}\))
-
NPY_LOG10E#
歐拉常數的以 10 為底的對數 (\(\frac{\ln(e)}{\ln(10)}\))
-
NPY_LOGE2#
2 的自然對數 (\(\ln(2)\))
-
NPY_LOGE10#
10 的自然對數 (\(\ln(10)\))
-
NPY_PI#
Pi (\(\pi\))
-
NPY_PI_2#
Pi 除以 2 (\(\frac{\pi}{2}\))
-
NPY_PI_4#
Pi 除以 4 (\(\frac{\pi}{4}\))
-
NPY_1_PI#
pi 的倒數 (\(\frac{1}{\pi}\))
-
NPY_2_PI#
pi 的倒數的兩倍 (\(\frac{2}{\pi}\))
-
NPY_EULER#
- 歐拉常數
\(\lim_{n\rightarrow\infty}({\sum_{k=1}^n{\frac{1}{k}}-\ln n})\)
低階浮點數操作#
這些對於精確的浮點數比較很有用。
-
double npy_nextafter(double x, double y)#
這是 C99 nextafter 的別名:從 x 傳回朝 y 方向的下一個可表示的浮點數值。單精度和延伸精度可使用後綴 f 和 l。
-
double npy_spacing(double x)#
這是與 Fortran intrinsic 等效的函數。傳回 x 與 x 的下一個可表示的浮點數值之間的距離,例如 spacing(1) == eps。nan 和 +/- inf 的 spacing 傳回 nan。單精度和延伸精度可使用後綴 f 和 l。
-
void npy_set_floatstatus_divbyzero()#
設定除以零浮點數例外
-
void npy_set_floatstatus_overflow()#
設定溢位浮點數例外
-
void npy_set_floatstatus_underflow()#
設定下溢浮點數例外
-
void npy_set_floatstatus_invalid()#
設定無效浮點數例外
-
int npy_get_floatstatus()#
取得浮點數狀態。傳回具有以下可能旗標的位元遮罩
NPY_FPE_DIVIDEBYZERO
NPY_FPE_OVERFLOW
NPY_FPE_UNDERFLOW
NPY_FPE_INVALID
請注意,
npy_get_floatstatus_barrier
更為可取,因為它可以防止激進的編譯器最佳化重新排序相對於設定狀態的程式碼的呼叫,這可能會導致不正確的結果。
-
int npy_get_floatstatus_barrier(char*)#
取得浮點數狀態。傳入本機變數的指標以防止激進的編譯器最佳化重新排序此函數呼叫相對於設定狀態的程式碼,這可能會導致不正確的結果。
傳回具有以下可能旗標的位元遮罩
NPY_FPE_DIVIDEBYZERO
NPY_FPE_OVERFLOW
NPY_FPE_UNDERFLOW
NPY_FPE_INVALID
-
int npy_clear_floatstatus()#
清除浮點數狀態。傳回先前的狀態遮罩。
請注意,
npy_clear_floatstatus_barrier
更為可取,因為它可以防止激進的編譯器最佳化重新排序相對於設定狀態的程式碼的呼叫,這可能會導致不正確的結果。
-
int npy_clear_floatstatus_barrier(char*)#
清除浮點數狀態。傳入本機變數的指標以防止激進的編譯器最佳化重新排序此函數呼叫。傳回先前的狀態遮罩。
支援複數#
已新增類似 C99 的複數函數。如果您希望實作可攜式 C 擴充功能,可以使用這些函數。自 NumPy 2.0 起,我們使用 C99 複數型別作為基礎型別
typedef double _Complex npy_cdouble;
typedef float _Complex npy_cfloat;
typedef long double _Complex npy_clongdouble;
MSVC 本身不支援 _Complex
型別,但已透過提供自己的實作來新增對 C99 complex.h
標頭檔的支援。因此,在 MSVC 下,將會使用等效的 MSVC 型別
typedef _Dcomplex npy_cdouble;
typedef _Fcomplex npy_cfloat;
typedef _Lcomplex npy_clongdouble;
由於 MSVC 仍然不支援用於初始化複數的 C99 語法,因此您需要限制使用與 C90 相容的語法,例如
/* a = 1 + 2i \*/
npy_complex a = npy_cpack(1, 2);
npy_complex b;
b = npy_log(a);
在 numpy/npy_math.h
中也新增了一些實用程式,以便擷取或設定複數的實部或虛部
npy_cdouble c;
npy_csetreal(&c, 1.0);
npy_csetimag(&c, 0.0);
printf("%d + %di\n", npy_creal(c), npy_cimag(c));
在 2.0.0 版本中變更: 所有 numpy 複數型別的基礎 C 型別已變更為使用 C99 複數型別。到目前為止,以下內容一直用於表示複數型別
typedef struct { double real, imag; } npy_cdouble;
typedef struct { float real, imag; } npy_cfloat;
typedef struct {npy_longdouble real, imag;} npy_clongdouble;
使用 struct
表示法可確保複數可以在所有平台上使用,即使是那些不支援內建複數型別的平台也是如此。這也表示必須隨 NumPy 運送靜態函式庫,以便為下游套件提供 C99 相容性層。然而,近年來,對原生複數型別的支援已大幅改進,MSVC 在 2019 年新增了對 complex.h
標頭檔的內建支援。
為了簡化跨版本相容性,已新增使用新設定 API 的巨集。
#define NPY_CSETREAL(z, r) npy_csetreal(z, r)
#define NPY_CSETIMAG(z, i) npy_csetimag(z, i)
相容性層也在 numpy/npy_2_complexcompat.h
中提供。它會檢查巨集是否存在,如果不存在,則會回復為 1.x 語法。
#include <numpy/npy_math.h>
#ifndef NPY_CSETREALF
#define NPY_CSETREALF(c, r) (c)->real = (r)
#endif
#ifndef NPY_CSETIMAGF
#define NPY_CSETIMAGF(c, i) (c)->imag = (i)
#endif
我們建議所有需要此功能的下游套件將相容性層程式碼複製貼上到自己的來源中並使用它,以便它們可以繼續支援 NumPy 1.x 和 2.x,而不會出現問題。另請注意,complex.h
標頭檔包含在 numpy/npy_common.h
中,這使得 complex
成為保留關鍵字。
在擴充功能中連結核心數學函式庫#
若要在您自己的 Python 擴充功能中使用 NumPy 隨附的作為靜態函式庫的核心數學函式庫,您需要將 npymath
編譯和連結選項新增至您的擴充功能。要採取的確切步驟將取決於您使用的建置系統。要採取的通用步驟是
將 numpy 包含目錄(=
np.get_include()
的值)新增至您的包含目錄,npymath
靜態函式庫位於 numpy 包含目錄旁邊的lib
目錄中(即pathlib.Path(np.get_include()) / '..' / 'lib'
)。將其新增至您的函式庫搜尋目錄,與
libnpymath
和libm
連結。
注意
請記住,當您進行交叉編譯時,您必須使用您要建置的平台的 numpy
,而不是建置機器的原生 numpy。否則,您會取得為錯誤架構建置的靜態函式庫。
當您使用 numpy.distutils
(已棄用) 進行建置時,請在您的 setup.py
中使用此程式碼
>>> from numpy.distutils.misc_util import get_info >>> info = get_info('npymath') >>> _ = config.add_extension('foo', sources=['foo.c'], extra_info=info)
換句話說,info
的用法與使用 blas_info
和 co 時完全相同。
當您使用 Meson 進行建置時,請使用
# Note that this will get easier in the future, when Meson has
# support for numpy built in; most of this can then be replaced
# by `dependency('numpy')`.
incdir_numpy = run_command(py3,
[
'-c',
'import os; os.chdir(".."); import numpy; print(numpy.get_include())'
],
check: true
).stdout().strip()
inc_np = include_directories(incdir_numpy)
cc = meson.get_compiler('c')
npymath_path = incdir_numpy / '..' / 'lib'
npymath_lib = cc.find_library('npymath', dirs: npymath_path)
py3.extension_module('module_name',
...
include_directories: inc_np,
dependencies: [npymath_lib],
半精度函數#
標頭檔 <numpy/halffloat.h>
提供用於處理 IEEE 754-2008 16 位元浮點數值的函數。雖然此格式通常不適用於數值計算,但它對於儲存需要浮點數但不需要太多精度的值很有用。它也可以用作了解浮點數捨入誤差本質的教育工具。
與其他型別一樣,NumPy 包含 16 位元浮點數的 typedef npy_half。與大多數其他型別不同,您不能在 C 中將其用作一般型別,因為它是 npy_uint16 的 typedef。例如,1.0 在 C 中看起來像 0x3c00,如果您在不同的帶符號零之間進行相等比較,您會得到 -0.0 != 0.0 (0x8000 != 0x0000),這是錯誤的。
由於這些原因,NumPy 提供了一個 API,用於處理可透過包含 <numpy/halffloat.h>
並連結到 npymath
來存取的 npy_half 值。對於未直接提供的函數(例如算術運算),慣用方法是轉換為 float 或 double,然後再轉換回來,如下例所示。
npy_half sum(int n, npy_half *array) {
float ret = 0;
while(n--) {
ret += npy_half_to_float(*array++);
}
return npy_float_to_half(ret);
}
外部連結
-
NPY_HALF_ZERO#
此巨集定義為正零。
-
NPY_HALF_PZERO#
此巨集定義為正零。
-
NPY_HALF_NZERO#
此巨集定義為負零。
-
NPY_HALF_ONE#
此巨集定義為 1.0。
-
NPY_HALF_NEGONE#
此巨集定義為 -1.0。
-
NPY_HALF_PINF#
此巨集定義為 +inf。
-
NPY_HALF_NINF#
此巨集定義為 -inf。
-
NPY_HALF_NAN#
此巨集定義為 NaN 值,保證其符號位未設定。
-
npy_half npy_float_to_half(float f)#
將單精度浮點數轉換為半精度浮點數。該值會四捨五入到最接近的可表示半精度值,平局情況會取最接近的偶數。如果該值太小或太大,則會設定系統的浮點數下溢或溢位位元。
-
npy_half npy_double_to_half(double d)#
將雙精度浮點數轉換為半精度浮點數。該值會四捨五入到最接近的可表示半精度值,平局情況會取最接近的偶數。如果該值太小或太大,則會設定系統的浮點數下溢或溢位位元。
-
npy_half npy_half_nextafter(npy_half x, npy_half y)#
這對於半精度浮點數與低階浮點數章節中描述的 npy_nextafter 和 npy_nextafterf 相同。
-
npy_uint16 npy_floatbits_to_halfbits(npy_uint32 f)#
低階函數,將儲存為 uint32 的 32 位元單精度浮點數,轉換為 16 位元半精度浮點數。
-
npy_uint16 npy_doublebits_to_halfbits(npy_uint64 d)#
低階函數,將儲存為 uint64 的 64 位元雙精度浮點數,轉換為 16 位元半精度浮點數。
-
npy_uint32 npy_halfbits_to_floatbits(npy_uint16 h)#
低階函數,將 16 位元半精度浮點數轉換為儲存為 uint32 的 32 位元單精度浮點數。
-
npy_uint64 npy_halfbits_to_doublebits(npy_uint16 h)#
低階函數,將 16 位元半精度浮點數轉換為儲存為 uint64 的 64 位元雙精度浮點數。