Skip to content

Latest commit

 

History

History
1543 lines (1009 loc) · 36.4 KB

np126_1076.md

File metadata and controls

1543 lines (1009 loc) · 36.4 KB

NumPy 核心库

原文:numpy.org/doc/1.26/reference/c-api/coremath.html

从 numpy 1.3.0 开始,我们正在致力于将纯 C 的“计算”代码与依赖于 Python 的代码分离。目标是使代码更清洁,并使其能够被 numpy 之外的其他扩展(例如 scipy 等)重用。

NumPy 核心数学库

numpy 核心数学库(‘npymath’)是这一方向的第一步。该库包含大多数与数学相关的 C99 功能,可用于 C99 支持不佳的平台。核心数学函数与 C99 函数具有相同的 API,除了npy_前缀。

可用的函数在<numpy/npy_math.h>中定义,疑惑时请参考该头文件。

注意

正在进行努力使npymath更小(因为随着时间的推移,编译器对 C99 的兼容性已经提高),并且更容易供应商化或作为仅头文件依赖。这将避免使用与下游包或最终用户使用的编译器不匹配的静态库的问题。详细信息,请参阅gh-20880

浮点数分类

NPY_NAN

此宏定义为 NaN(非数),保证符号位未设置(“正”NaN)。相应的单精度和扩展精度宏可分别添加 F 和 L 后缀获得。

NPY_INFINITY

此宏定义为正无穷大。相应的单精度和扩展精度宏可分别添加 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中找到。添加fl后缀即可获得单精度和扩展精度。

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))

NPY_PI_2

π除以 2 ((\frac{\pi}{2}))

NPY_PI_4

π除以 4 ((\frac{\pi}{4}))

NPY_1_PI

π的倒数 ((\frac{1}{\pi}))

NPY_2_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 内在函数的函数。返回 x 和下一个可表示的浮点值之间的距离,例如,spacing(1) == eps。 nan 和+/- inf 的间距返回 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

新版本为 1.15.0。

int npy_clear_floatstatus()

清除浮点状态。返回先前的状态掩码。

请注意,npy_clear_floatstatus_barrier 更可取,因为它可以防止激进的编译器优化重新排列调用相对于设置状态的代码,这可能导致不正确的结果。

int npy_clear_floatstatus_barrier(char*)

清除浮点状态。会传递一个指向本地变量的指针,以防止激进的编译器优化重新排列此函数调用相对于设置状态的代码。返回先前的状态掩码。

新版本为 1.15.0。

复数函数

添加了类似于 C99 的复数函数。 如果您希望实现可移植的 C 扩展,则可以使用这些。 由于我们仍然支持不支持 C99 复数类型的平台(最重要的是 Windows,到 2022 年 11 月,MSVC 不支持 C99 复数类型),因此您需要限制为 C90 兼容的语法,例如:

/* a = 1 + 2i \*/
npy_complex  a  =  npy_cpack(1,  2);
npy_complex  b;

b  =  npy_log(a); 

在扩展中链接核心数学库

要在您自己的 Python 扩展中使用 NumPy 作为静态库提供的核心数学库,您需要向您的扩展添加 npymath 编译和链接选项。采取的确切步骤将取决于您使用的构建系统。采取的通用步骤包括:

  1. 将 numpy 包含目录(即np.get_include()的值)添加到您的包含目录中,

  2. npymath静态库位于紧邻 numpy 包含目录的lib目录中(即pathlib.Path(np.get_include()) / '..' / 'lib')。将其添加到您的库搜索目录中,

  3. 链接到libnpymathlibm

请记住,当您进行交叉编译时,必须使用适用于您构建的平台的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等完全相同。

当您使用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 位浮点数的 npy_half 的 typedef。与大多数其他类型不同,您不能在 C 中将其用作普通类型,因为它是 npy_uint16 的 typedef。例如,1.0 在 C 中看起来像 0x3c00,如果您在不同的带符号零之间进行相等比较,您会得到-0.0 != 0.0(0x8000 != 0x0000),这是不正确的。

出于这些原因,NumPy 提供了一个 API 来处理通过包括<numpy/halffloat.h>和链接到npymath可访问的 npy_half 值。对于没有直接提供的函数,如算术运算,首选方法是转换为 float 或 double,然后再次转换为 half,就像以下示例一样。

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

这个宏被定义为正无穷。

NPY_HALF_NINF

这个宏被定义为负无穷。

NPY_HALF_NAN

这个宏被定义为 NaN 值,保证其符号位未设置。

float npy_half_to_float( h)

将半精度浮点数转换为单精度浮点数。

double npy_half_to_double( h)

将半精度浮点数转换为双精度浮点数。

npy_float_to_half(float f)

将单精度浮点数转换为半精度浮点数。值四舍五入为最接近的可表示的一半,平局取最近的偶数。如果值太小或者太大,系统的浮点下溢或上溢位将被设置。

npy_double_to_half(double d)

将双精度浮点数转换为半精度浮点数。值四舍五入到最接近的可表示的一半,平局取最近的偶数。如果值太小或太大,系统的浮点下溢或上溢位将被设置。

int npy_half_eq( h1, h2)

比较两个半精度浮点数(h1 == h2)。

int npy_half_ne( h1, h2)

比较两个半精度浮点数(h1 != h2)。

int npy_half_le( h1, h2)

比较两个半精度浮点数(h1 <= h2)。

int npy_half_lt( h1, h2)

比较两个半精度浮点数(h1 < h2)。

int npy_half_ge( h1, h2)

比较两个半精度浮点数(h1 >= h2)。

int npy_half_gt( h1, h2)

比较两个半精度浮点数(h1 > h2)。

int npy_half_eq_nonan( h1, h2)

比较两个已知不是 NaN 的半精度浮点数(h1 == h2)。如果值是 NaN,则结果未定义。

int npy_half_lt_nonan( h1, h2)

比较两个已知不是 NaN 的半精度浮点数(h1 < h2)。如果值是 NaN,则结果未定义。

int npy_half_le_nonan( h1, h2)

比较两个已知不是 NaN 的半精度浮点数(h1 <= h2)。如果值是 NaN,则结果未定义。

int npy_half_iszero( h)

测试半精度浮点数是否值为零。这可能比调用 npy_half_eq(h, NPY_ZERO)要稍快。

int npy_half_isnan( h)

测试半精度浮点数是否是 NaN。

int npy_half_isinf( h)

测试半精度浮点数是否是正或负无穷大。

int npy_half_isfinite( h)

测试半精度浮点数是否是有限的(不是 NaN 或 Inf)。

int npy_half_signbit( h)

返回 1,如果 h 是负数,否则返回 0。

npy_half_copysign( x, y)

返回具有从 y 复制的符号位的 x 的值。适用于任何值,包括 Inf 和 NaN。

npy_half_spacing( h)

这与低级浮点部分中描述的 npy_spacing 和 npy_spacingf 对于半精度浮点数是相同的。

npy_half_nextafter( x, y)

这与低级浮点部分中描述的 npy_nextafter 和 npy_nextafterf 对于半精度浮点数是相同的。

npy_floatbits_to_halfbits( f)

低级函数,将 32 位单精度浮点数,存储为 uint32,转换为 16 位半精度浮点数。

npy_doublebits_to_halfbits( d)

低级函数,将 64 位双精度浮点数,存储为 uint64,转换为 16 位半精度浮点数。

npy_halfbits_to_floatbits( h)

低级函数,将一个 16 位半精度浮点数转换为 32 位单精度浮点数,存储为 uint32。

npy_halfbits_to_doublebits( h)

将一个 16 位半精度浮点数转换为 64 位双精度浮点数,存储为 uint64 的低级函数。

NumPy 核心数学库

Numpy 核心数学库(‘npymath’)是朝这个方向迈出的第一步。该库包含大多数与数学相关的 C99 功能,可用于 C99 支持不佳的平台。核心数学函数的 API 与 C99 函数相同,除了npy_*前缀。

可用函数在<numpy/npy_math.h>中定义-当有疑问时,请参考此头文件。

注意

现在正努力使 npymath 更小(因为随着时间的推移,编译器的 C99 兼容性已经得到改善),并且更容易供应商使用或作为头文件依赖。这将避免使用与下游包或最终用户所用编译器不匹配的静态库的发货问题。有关详细信息,请参见 gh-20880

浮点数分类

NPY_NAN

此宏被定义为 NaN(不是一个数),并且保证符号位未设置('正' NaN)。相应的单精度和扩展精度宏可用后缀 F 和 L。

NPY_INFINITY

此宏被定义为正无穷。相应的单精度和扩展精度宏可用后缀 F 和 L。

NPY_PZERO

此宏被定义为正零。相应的单精度和扩展精度宏可用后缀 F 和 L。

NPY_NZERO

此宏被定义为负零(即符号位设置为 1)。相应的单精度和扩展精度宏可用后缀 F 和 L。

npy_isnan(x)

这是 C99 的 isnan 的别名:适用于单精度、双精度和扩展精度,并在 x 是 NaN 时返回非零值。

npy_isfinite(x)

这是 C99 的 isfinite 的别名:适用于单精度、双精度和扩展精度,并且在 x 既不是 NaN 也不是无穷时返回非零值。

npy_isinf(x)

这是 C99 的 isinf 的别名:适用于单精度、双精度和扩展精度,并且在 x 是无穷(正无穷和负无穷)时返回非零值。

npy_signbit(x)

这是 C99 的 signbit 的别名:适用于单精度、双精度和扩展精度,并且在 x 的符号位设置时返回非零值(即数是负数)。

npy_copysign(x, y)

这是 C99 的 copysign 的别名:返回与 y 相同符号的 x。适用于任何值,包括 inf 和 nan。单精度和扩展精度可用后缀 f 和 l。

有用的数学常数

以下数学常数可在 npy_math.h 中使用。单精度和扩展精度也可通过添加 fl 后缀分别使用。

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))

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

2 乘以 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 内置函数的函数。返回与 x 和下一个可表示的浮点值之间的距离,例如,spacing(1) == eps。 nan 和+/- inf 的间距返回 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

版本 1.15.0 中新增。

int npy_clear_floatstatus()

清除浮点状态。返回以前的状态掩码。

请注意,npy_clear_floatstatus_barrier更可取,因为它可以防止激进的编译器优化重新排列调用相对于设置状态的代码,这可能导致不正确的结果。

int npy_clear_floatstatus_barrier(char*)

清除浮点状态。传递给本地变量的指针可以防止激进的编译器优化重新排列此函数调用。返回以前的状态掩码。

版本 1.15.0 中新增。

复杂函数

添加了类似 C99 的复杂函数。如果您希望实现可移植的 C 扩展程序,则可以使用这些。由于我们仍然支持没有 C99 复杂类型的平台(最重要的是 Windows,在那里,截至 2022 年 11 月,MSVC 不支持 C99 复杂类型),您需要限制为 C90 兼容语法,例如:

/* a = 1 + 2i \*/
npy_complex  a  =  npy_cpack(1,  2);
npy_complex  b;

b  =  npy_log(a); 

在扩展中链接核心数学库

要在自己的 Python 扩展中使用 NumPy 提供的核心数学库作为静态库,您需要将 npymath 编译和链接选项添加到您的扩展程序中。要采取的确切步骤将取决于您正在使用的构建系统。要采取的通用步骤包括:

  1. 将 numpy 包括目录(= np.get_include()的值)添加到您的包括目录中,

  2. npymath静态库位于紧挨着 numpy 包括目录的lib目录中(即,pathlib.Path(np.get_include()) / '..' / 'lib')。将其添加到您的库搜索目录中,

  3. 使用libnpymathlibm进行链接。

注意

请记住,在交叉编译时,必须使用适用于您要构建的平台的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等完全相同。

在构建时使用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 值,保证其符号位未设置。

float npy_half_to_float( h)

将半精度浮点数转换为单精度浮点数。

double npy_half_to_double( h)

将半精度浮点数转换为双精度浮点数。

npy_float_to_half(float f)

将单精度浮点数转换为半精度浮点数。该值四舍五入为最接近的可表示的半精度数,如果太小或太大,则系统的浮点下溢或溢出位将被设置。

npy_double_to_half(double d)

将双精度浮点数转换为半精度浮点数。该值四舍五入为最接近的可表示的半精度数,如果太小或太大,则系统的浮点下溢或溢出位将被设置。

int npy_half_eq( h1, h2)

比较两个半精度浮点数(h1 == h2)。

int npy_half_ne( h1, h2)

比较两个半精度浮点数(h1 != h2)。

int npy_half_le( h1, h2)

比较两个半精度浮点数(h1 <= h2)。

int npy_half_lt( h1, h2)

比较两个半精度浮点数(h1 < h2)。

int npy_half_ge( h1, h2)

比较两个半精度浮点数(h1 >= h2)。

int npy_half_gt( h1, h2)

比较两个半精度浮点数(h1 > h2)。

int npy_half_eq_nonan( h1, h2)

比较已知不是 NaN 的两个半精度浮点数(h1 == h2)。如果值为 NaN,则结果是未定义的。

int npy_half_lt_nonan( h1, h2)

比较已知不是 NaN 的两个半精度浮点数(h1 < h2)。如果值为 NaN,则结果是未定义的。

int npy_half_le_nonan( h1, h2)

比较已知不是 NaN 的两个半精度浮点数(h1 <= h2)。如果值为 NaN,则结果是未定义的。

int npy_half_iszero( h)

测试半精度浮点数是否等于零。这可能比调用 npy_half_eq(h, NPY_ZERO) 更快。

int npy_half_isnan( h)

测试半精度浮点数是否为 NaN。

int npy_half_isinf( h)

测试半精度浮点数是否为正负无穷。

int npy_half_isfinite( h)

测试半精度浮点数是否有限(非 NaN 或 Inf)。

int npy_half_signbit( h)

如果 h 为负,则返回 1,否则返回 0。

npy_half_copysign( x, y)

返回从 y 复制的符号位的 x 值。适用于任何值,包括 Inf 和 NaN。

npy_half_spacing( h)

这与低级浮点部分中描述的 npy_spacing 和 npy_spacingf 类似。

npy_half_nextafter( x, y)

这与低级浮点部分中描述的 npy_nextafter 和 npy_nextafterf 类似,用于半精度浮点数。

npy_floatbits_to_halfbits( f)

将以 uint32 存储的 32 位单精度浮点数转换为 16 位半精度浮点数的低级功能。

npy_doublebits_to_halfbits( d)

将以 uint64 存储的 64 位双精度浮点数转换为 16 位半精度浮点数的低级功能。

npy_halfbits_to_floatbits( h)

将 16 位半精度浮点数转换为以 uint32 存储的 32 位单精度浮点数的低级功能。

npy_halfbits_to_doublebits( h)

将 16 位半精度浮点数转换为以 uint64 存储的 64 位双精度浮点数的低级功能。

浮点分类

NPY_NAN

此宏被定义为 NaN(非数字),并保证符号位未设置('正' NaN)。相应的单精度和扩展精度宏可在后缀 F 和 L 中使用。

NPY_INFINITY

此宏被定义为正无穷。相应的单精度和扩展精度宏可在后缀 F 和 L 中使用。

NPY_PZERO

此宏被定义为正零。相应的单精度和扩展精度宏可在后缀 F 和 L 中使用。

NPY_NZERO

此宏被定义为负零(即符号位设置)。相应的单精度和扩展精度宏可在后缀 F 和 L 中使用。

npy_isnan(x)

这是 C99 isnan 的别名:适用于单精度、双精度和扩展精度,并在 x 为 NaN 时返回非零值。

npy_isfinite(x)

这是 C99 isfinite 的别名:适用于单精度、双精度和扩展精度,并在 x 既非 NaN 也非无穷时返回非零值。

npy_isinf(x)

这是 C99 isinf 的别名:适用于单精度、双精度和扩展精度,并在 x 是无限值(正负)时返回非零值。

npy_signbit(x)

这是 C99 signbit 的别名:适用于单精度、双精度和扩展精度,并在 x 有符号位设置时(即数字为负)返回非零值。

npy_copysign(x, y)

这是 C99 copysign 的别名:返回与 y 相同符号的 x。适用于任何值,包括 inf 和 nan。单精度和扩展精度可在后缀 f 和 l 中使用。

有用的数学常量

以下数学常量在npy_math.h中可用。也可以通过添加fl后缀来使用单精度和扩展精度。

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))

NPY_PI_2

π除以 2((\frac{\pi}{2}))

NPY_PI_4

常数π除以 4((\frac{\pi}{4}))

NPY_1_PI

π的倒数((\frac{1}{\pi}))

NPY_2_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 内在函数的函数。返回 x 和 x 的下一个可表示的浮点值之间的距离,例如 spacing(1) == eps。 nan 和+/- inf 的间距返回 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

在版本 1.15.0 中新增。

int npy_clear_floatstatus()

清除浮点状态。返回先前的状态掩码。

请注意,npy_clear_floatstatus_barrier更可取,因为它会防止编译器优化重新安排调用相对于设置状态的代码,这可能导致不正确的结果。

int npy_clear_floatstatus_barrier(char*)

清除浮点状态。传入一个本地变量的指针以防止过于激进的编译器优化重新安排此函数调用。返回先前的状态掩码。

在版本 1.15.0 中新增。

复杂函数

已添加类似于 C99 的复数函数。如果你希望实现可移植的 C 扩展,可以使用这些函数。由于我们仍然支持没有 C99 复数类型的平台(最重要的是 Windows,截至 2022 年 11 月,MSVC 不支持 C99 复数类型),你需要限制为兼容 C90 的语法,例如:

/* a = 1 + 2i \*/
npy_complex  a  =  npy_cpack(1,  2);
npy_complex  b;

b  =  npy_log(a); 

在扩展中链接核心数学库

要在你自己的 Python 扩展中使用 NumPy 提供的核心数学库作为静态库,你需要为你的扩展添加npymath编译和链接选项。具体的步骤将取决于你使用的构建系统。一般的步骤如下:

  1. 将 numpy 的包含目录(即np.get_include()的值)添加到你的包含目录中,

  2. npymath静态库位于 numpy 的包含目录旁边的lib目录中(即pathlib.Path(np.get_include()) / '..' / 'lib')。将其添加到你的库搜索目录中,

  3. 链接时使用libnpymathlibm

注意

请记住,当你交叉编译时,你必须使用与你构建的平台相关的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等是完全相同的。

当你使用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 包括一个npy_half的类型定义,用于表示 16 位浮点数。与大多数其他类型不同,你不能在 C 中将它用作普通类型,因为它是npy_uint16的一个类型定义。例如,对于 C 来说,1.0 看起来像 0x3c00,如果你在不同的有符号零之间进行相等比较,你将得到-0.0 != 0.0 (0x8000 != 0x0000),这是不正确的。

出于这些原因,NumPy 提供了一个 API 来处理通过包含<numpy/halffloat.h>和链接到npymath可访问的npy_half值。对于那些没有直接提供的函数,例如算术运算,首选方法是先转换为浮点数或双精度数,然后再转换回来,如下面的例子所示。

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 值,保证其符号位未设置。

float npy_half_to_float( h)

将半精度浮点数转换为单精度浮点数。

double npy_half_to_double( h)

将半精度浮点数转换为双精度浮点数。

npy_float_to_half(float f)

将单精度浮点数转换为半精度浮点数。该值四舍五入为最接近的可表示的一半,如果值太小或太大,则系统的浮点下溢位或上溢位将被设置。

npy_double_to_half(double d)

将双精度浮点数转换为半精度浮点数。该值四舍五入为最接近的可表示的一半,如果值太小或太大,则系统的浮点下溢位或上溢位将被设置。

int npy_half_eq( h1, h2)

比较两个半精度浮点数(h1 == h2)。

int npy_half_ne( h1, h2)

比较两个半精度浮点数(h1 != h2)。

int npy_half_le( h1, h2)

比较两个半精度浮点数(h1 <= h2)。

int npy_half_lt( h1, h2)

比较两个半精度浮点数(h1 < h2)。

int npy_half_ge( h1, h2)

比较两个半精度浮点数(h1 >= h2)。

int npy_half_gt( h1, h2)

比较两个半精度浮点数(h1 > h2)。

int npy_half_eq_nonan( h1, h2)

比较已知不为 NaN 的两个半精度浮点数(h1 == h2)。如果一个值是 NaN,则结果是未定义的。

int npy_half_lt_nonan( h1, h2)

比较已知不为 NaN 的两个半精度浮点数(h1 < h2)。如果一个值是 NaN,则结果是未定义的。

int npy_half_le_nonan( h1, h2)

比较已知不为 NaN 的两个半精度浮点数(h1 <= h2)。如果一个值是 NaN,则结果是未定义的。

int npy_half_iszero( h)

检测半精度浮点数是否具有等于零的值。这可能比调用 npy_half_eq(h, NPY_ZERO)稍微快一些。

int npy_half_isnan( h)

检测半精度浮点数是否为 NaN。

int npy_half_isinf( h)

检测半精度浮点数是否为正或负 Inf。

int npy_half_isfinite( h)

检测半精度浮点数是否有限(不是 NaN 或 Inf)。

int npy_half_signbit( h)

如果 h 为负则返回 1,否则返回 0。

npy_half_copysign( x, y)

将 x 的符号位从 y 中复制的值返回。适用于任何值,包括 Inf 和 NaN。

npy_half_spacing( h)

这与低级浮点部分中描述的 npy_spacing 和 npy_spacingf 对于半精度浮点数是相同的。

npy_half_nextafter( x, y)

这与低级浮点部分中描述的 npy_nextafter 和 npy_nextafterf 对于半精度浮点数是相同的。

npy_floatbits_to_halfbits( f)

将 32 位单精度浮点数,存储为 uint32,转换为 16 位半精度浮点数的低级函数。

npy_doublebits_to_halfbits( d)

将 64 位双精度浮点数,存储为 uint64,转换为 16 位半精度浮点数的低级函数。

npy_halfbits_to_floatbits( h)

将 16 位半精度浮点数转换为 32 位单精度浮点数(存储为 uint32)的低级函数。

npy_halfbits_to_doublebits( h)

将 16 位半精度浮点数转换为 64 位双精度浮点数(存储为 uint64)的低级函数。