跳到主要内容

pico-double

优化的双精度浮点函数。

详细描述

应用程序可以通过依赖 pico_double 库,对程序中使用的浮点运算例程进行比编译器所提供的更深层次的控制。用户可能希望这样做的原因包括:

  1. 使用 RP2-series 设备 bootrom 或 SDK 提供的优化软件实现

  2. 使用利用 RP2-series 自定义硬件加速的优化软硬件组合实现

  3. 控制 C 编译器/库代码体积膨胀的程度

  4. 确保程序中完全不调用浮点运算

pico_double 库有三种主要版本:

  1. none - 所有浮点操作都会引发 panic —— 不包含任何双精度浮点代码

  2. compiler - 不提供自定义函数;所有双精度浮点运算均由 C 编译器/库处理

  3. pico - 适用于该平台的最小且最快的版本,并附带额外功能(如定点数转换),详见下文

用户可以通过设置 CMake 全局变量 PICO_DEFAULT_DOUBLE_IMPL=compiler,或使用 CMake 函数 pico_set_double_implementation(<TARGET> compiler) 来控制使用哪个版本(例如 pico_double compiler)。注意:若两者均未设置,默认使用 pico_double pico

在 RP2040 上,pico_double pico 使用来自 bootrom 和 SDK 的优化手写实现,涵盖基本双精度浮点运算和浮点数学库函数。这些实现通常比 C 编译器/库提供的更快、更小,但不支持完全符合规范的浮点实现的所有特性;不过,对于大多数使用场景而言通常已足够。

在 RP2350 上,pico_double pico 使用 RP2350 DCP 指令(双精度协处理器)实现基本算术函数的快速版本,并为三角函数和科学计算函数提供优化的 M33 实现。这些实现通常比 C 编译器/库提供的更快、更小,但不支持完全符合规范的浮点实现的所有特性;不过,对于大多数使用场景而言通常已足够。

在 Arm 上,使用 pico_double pico 时,以下编译器内置函数和数学库函数将提供(替换性的)优化实现:

  • 基本算术:

__aeabi_dadd, __aeabi_ddiv, __aeabi_dmul, __aeabi_drsub, __aeabi_dsub

  • 比较:

__aeabi_cfcmpeq, __aeabi_cfrcmple, __aeabi_cfcmple, __aeabi_dcmpeq, __aeabi_dcmplt, __aeabi_dcmple, __aeabi_dcmpge, __aeabi_dcmpgt, __aeabi_dcmpun

  • (u)int32 <-> double:

__aeabi_i2d, __aeabi_ui2d, __aeabi_d2iz, __aeabi_d2uiz

  • (u)int64 <-> double:

__aeabi_l2d, __aeabi_ul2d, __aeabi_d2lz, __aeabi_d2ulz

  • double -> float:

__aeabi_d2d

  • 基本三角函数:

sqrt, cos, sin, tan, atan2, exp, log

  • 三角函数和科学计算函数:

ldexp, copysign, trunc, floor, ceil, round, asin, acos, atan, sinh, cosh, tanh, asinh, acosh, atanh, exp2, log2, exp10, log10, pow, hypot, cbrt, fmod, drem, remainder, remquo, expm1, log1p, fma

  • GNU 扩展:

sincos

在 Arm 上,使用 pico_double pico 时还提供以下额外的优化函数,所有这些函数在从浮点类型转换时,对于过大的输入会饱和到最近的可表示值:

  • 与整数类型之间的转换:

    • (u)int -> double(四舍五入到最近): int2double, uint2double, int642double, uint642double

    • (u)double -> int(向零舍入): double2int_z, double2uint_z, double2int64_z, double2uint64_z

    • (u)double -> int(向负无穷舍入): double2int, double2uint, double2int64, double2uint64

  • 与定点整数之间的转换:

    • (u)fix -> double(四舍五入到最近): fix2double, ufix2double, fix642double, ufix642double

    • double -> (u)fix(向零舍入): double2fix_z, double2ufix_z, double2fix64_z, double2ufix64_z

    • double -> (u)fix(向负无穷舍入): double2fix, double2ufix, double2fix64, double2ufix64

  • 科学函数:

powint

  • 不能正确舍入的更快版本的除法和平方根函数:

ddiv_fast, sqrt_fast

  • 更快的非融合乘加:

mla/fma_fast

在 RISC-V 上,不支持自定义双精度浮点运算,因此 pico_double pico 等同于 pico_double compiler

  • #define PICO_DOUBLE_HAS_INT32_TO_DOUBLE_CONVERSIONS 1
  • #define PICO_DOUBLE_HAS_INT64_TO_DOUBLE_CONVERSIONS 1
  • #define PICO_DOUBLE_HAS_DOUBLE_TO_INT32_Z_CONVERSIONS 1
  • #define PICO_DOUBLE_HAS_DOUBLE_TO_INT64_Z_CONVERSIONS 1
  • #define PICO_DOUBLE_HAS_FIX32_TO_DOUBLE_CONVERSIONS 1
  • #define PICO_DOUBLE_HAS_FIX64_TO_DOUBLE_CONVERSIONS 1
  • #define PICO_DOUBLE_HAS_DOUBLE_TO_FIX32_Z_CONVERSIONS 1
  • #define PICO_DOUBLE_HAS_DOUBLE_TO_FIX64_Z_CONVERSIONS 1
  • #define PICO_DOUBLE_HAS_DOUBLE_TO_INT32_M_CONVERSIONS 1
  • #define PICO_DOUBLE_HAS_DOUBLE_TO_INT64_M_CONVERSIONS 1
  • #define PICO_DOUBLE_HAS_DOUBLE_TO_FIX32_M_CONVERSIONS 1
  • #define PICO_DOUBLE_HAS_DOUBLE_TO_FIX64_M_CONVERSIONS 1
  • #define PICO_DOUBLE_HAS_DDIV_FAST 1
  • #define PICO_DOUBLE_HAS_SQRT_FAST 1
  • #define PICO_DOUBLE_HAS_FMA_FAST 1
  • #define PICO_DOUBLE_HAS_POWINT 1

函数

  • double int2double (int32_t i): 将有符号 32 位整数转换为最近的双精度浮点数。
  • double uint2double (uint32_t u): 将无符号 32 位整数转换为最近的双精度浮点数。
  • double int642double (int64_t i): 将有符号 64 位整数转换为最近的双精度浮点数。
  • double uint642double (uint64_t u): 将无符号 64 位整数转换为最近的双精度浮点数。
  • int32_t double2int_z (double d): 将双精度浮点数转换为有符号 32 位整数,向零舍入。在 Arm 上,此转换对超出范围的输入是饱和的(到 INT32_MAX/INT32_MIN),但使用 pico_double compiler 时除外。
  • uint32_t double2uint_z (double d): 将双精度浮点数转换为无符号 32 位整数,向零舍入。在 Arm 上,此转换对超出范围的输入是饱和的(到 UINT32_MAX/UINT32_MIN),但使用 pico_double compiler 时除外。
  • int64_t double2int64_z (double d): 将双精度浮点数转换为有符号 64 位整数,向零舍入。在 Arm 上,此转换对超出范围的输入是饱和的(到 INT64_MAX/INT64_MIN),但使用 pico_double compiler 时除外。
  • uint64_t double2uint64_z (double d): 将双精度浮点数转换为无符号 64 位整数,向零舍入。在 Arm 上,此转换对超出范围的输入是饱和的(到 UINT64_MAX/UINT64_MIN),但使用 pico_double compiler 时除外。
  • double fix2double (int32_t m, int e): 将给定小数位数的有符号 32 位定点整数转换为最近的双精度浮点数。超出范围的输入将转换为 +/- 无穷大。
  • double ufix2double (uint32_t m, int e): 将给定小数位数的无符号 32 位定点整数转换为最近的双精度浮点数。超出范围的输入将转换为 +无穷大。
  • double fix642double (int64_t m, int e): 将给定小数位数的有符号 64 位定点整数转换为最近的双精度浮点数。超出范围的输入将转换为 +/- 无穷大。
  • double ufix642double (uint64_t m, int e): 将给定小数位数的无符号 64 位定点整数转换为最近的双精度浮点数。超出范围的输入将转换为 +无穷大。
  • int32_t double2fix_z (double d, int e): 将双精度浮点数转换为给定小数位数的有符号 32 位定点整数,向零舍入。在 Arm 上,此转换对超出范围的输入是饱和的(到 INT32_MAX/INT32_MIN),但使用 pico_double compiler 时除外。
  • uint32_t double2ufix_z (double d, int e): 将双精度浮点数转换为给定小数位数的无符号 32 位定点整数,向零舍入。此转换对超出范围的输入是饱和的(到 UINT32_MAX/UINT32_MIN)。
  • int64_t double2fix64_z (double d, int e): 将双精度浮点数转换为给定小数位数的有符号 64 位定点整数,向零舍入。在 Arm 上,此转换对超出范围的输入是饱和的(到 INT64_MAX/INT64_MIN),但使用 pico_double compiler 时除外。
  • uint64_t double2ufix64_z (double d, int e): 将双精度浮点数转换为给定小数位数的无符号 64 位定点整数,向零舍入。此转换对超出范围的输入是饱和的(到 UINT64_MAX/UINT64_MIN)。
  • int32_t double2int (double d): 将双精度浮点数转换为有符号 32 位整数,向负无穷舍入。此转换对超出范围的输入是饱和的(到 INT32_MAX/INT32_MIN)。
  • uint32_t double2uint (double d): 将双精度浮点数转换为无符号 32 位整数,向负无穷舍入。此转换对超出范围的输入是饱和的(到 UINT32_MAX/UINT32_MIN)。
  • int64_t double2int64 (double d): 将双精度浮点数转换为有符号 64 位整数,向负无穷舍入。此转换对超出范围的输入是饱和的(到 INT64_MAX/INT64_MIN)。
  • uint64_t double2uint64 (double d): 将双精度浮点数转换为无符号 64 位整数,向负无穷舍入。此转换对超出范围的输入是饱和的(到 UINT64_MAX/UINT64_MIN)。
  • int32_t double2fix (double d, int e): 将双精度浮点数转换为给定小数位数的有符号 32 位定点整数,向负无穷舍入。此转换对超出范围的输入是饱和的(到 INT32_MAX/INT32_MIN)。
  • uint32_t double2ufix (double d, int e): 将双精度浮点数转换为给定小数位数的无符号 32 位定点整数,向负无穷舍入。此转换对超出范围的输入是饱和的(到 UINT32_MAX/UINT32_MIN)。
  • int64_t double2fix64 (double d, int e): 将双精度浮点数转换为给定小数位数的有符号 64 位定点整数,向负无穷舍入。此转换对超出范围的输入是饱和的(到 INT64_MAX/INT64_MIN)。
  • uint64_t double2ufix64 (double d, int e): 将双精度浮点数转换为给定小数位数的无符号 64 位定点整数,向负无穷舍入。此转换对超出范围的输入是饱和的(到 UINT64_MAX/UINT64_MIN)。
  • double exp10 (double x): 计算 10.0 的给定次幂。
  • void sincos (double x, double *sinx, double *cosx): 高效地返回一个角度的正弦和余弦值。
  • double powint (double x, int32_t y): 将浮点数提升到整数幂。
  • double ddiv_fast (double n, double d): 执行精度降低的快速浮点除法。
  • double sqrt_fast (double d): 执行精度降低的快速浮点平方根。
  • double fma_fast (double x, double y, double z): 执行精度降低的快速(非融合)乘加(x * y + z)。
  • double mla (double x, double y, double z): 执行精度降低的快速乘加(x * y + z)(非融合乘加)。这是 fma_fast 的另一个名称。

宏定义文档

PICO_DOUBLE_HAS_INT32_TO_DOUBLE_CONVERSIONS

#define PICO_DOUBLE_HAS_INT32_TO_DOUBLE_CONVERSIONS 1

int2doubleuint2double 可用则设置。

PICO_DOUBLE_HAS_INT64_TO_DOUBLE_CONVERSIONS

#define PICO_DOUBLE_HAS_INT64_TO_DOUBLE_CONVERSIONS 1

int642doubleuint642double 可用则设置。

PICO_DOUBLE_HAS_DOUBLE_TO_INT32_Z_CONVERSIONS

#define PICO_DOUBLE_HAS_DOUBLE_TO_INT32_Z_CONVERSIONS 1

double2int_zdouble2uint_z 可用则设置(向零舍入)

PICO_DOUBLE_HAS_DOUBLE_TO_INT64_Z_CONVERSIONS

#define PICO_DOUBLE_HAS_DOUBLE_TO_INT64_Z_CONVERSIONS 1

double2int64_zdouble2uint64_z 可用则设置(向零舍入)

PICO_DOUBLE_HAS_FIX32_TO_DOUBLE_CONVERSIONS

#define PICO_DOUBLE_HAS_FIX32_TO_DOUBLE_CONVERSIONS 1

fix2doubleufix2double 可用则设置。

PICO_DOUBLE_HAS_FIX64_TO_DOUBLE_CONVERSIONS

#define PICO_DOUBLE_HAS_FIX64_TO_DOUBLE_CONVERSIONS 1

fix642doubleufix642double 可用则设置。

PICO_DOUBLE_HAS_DOUBLE_TO_FIX32_Z_CONVERSIONS

#define PICO_DOUBLE_HAS_DOUBLE_TO_FIX32_Z_CONVERSIONS 1

double2fix_zdouble2ufix_z 可用则设置(向零舍入)

PICO_DOUBLE_HAS_DOUBLE_TO_FIX64_Z_CONVERSIONS

#define PICO_DOUBLE_HAS_DOUBLE_TO_FIX64_Z_CONVERSIONS 1

double2fix64_zdouble2ufix64_z 可用则设置(向零舍入)

PICO_DOUBLE_HAS_DOUBLE_TO_INT32_M_CONVERSIONS

#define PICO_DOUBLE_HAS_DOUBLE_TO_INT32_M_CONVERSIONS 1

double2intdouble2uint 可用则设置(向负无穷舍入)

PICO_DOUBLE_HAS_DOUBLE_TO_INT64_M_CONVERSIONS

#define PICO_DOUBLE_HAS_DOUBLE_TO_INT64_M_CONVERSIONS 1

double2int64double2uint64 可用则设置(向负无穷舍入)

PICO_DOUBLE_HAS_DOUBLE_TO_FIX32_M_CONVERSIONS

#define PICO_DOUBLE_HAS_DOUBLE_TO_FIX32_M_CONVERSIONS 1

double2fixdouble2ufix 可用则设置(向负无穷舍入)

PICO_DOUBLE_HAS_DOUBLE_TO_FIX64_M_CONVERSIONS

#define PICO_DOUBLE_HAS_DOUBLE_TO_FIX64_M_CONVERSIONS 1

double2fix64double2ufix64 可用则设置(向负无穷舍入)

PICO_DOUBLE_HAS_DDIV_FAST

#define PICO_DOUBLE_HAS_DDIV_FAST 1

ddiv_fast 可用则设置。

PICO_DOUBLE_HAS_SQRT_FAST

#define PICO_DOUBLE_HAS_SQRT_FAST 1

sqrt_fast 可用则设置。

PICO_DOUBLE_HAS_FMA_FAST

#define PICO_DOUBLE_HAS_FMA_FAST 1

fma_fast 可用则设置。

PICO_DOUBLE_HAS_POWINT

#define PICO_DOUBLE_HAS_POWINT 1

若 powint 可用则设置。

函数文档

ddiv_fast

double ddiv_fast (double n, double d)

执行精度降低的快速浮点除法。

double2fix

int32_t double2fix (double d, int e)

将双精度浮点数转换为给定小数位数的有符号 32 位定点整数,向负无穷舍入。此转换对超出范围的输入是饱和的(到 INT32_MAX/INT32_MIN)。

double2fix64

int64_t double2fix64 (double d, int e)

将双精度浮点数转换为给定小数位数的有符号 64 位定点整数,向负无穷舍入。此转换对超出范围的输入是饱和的(到 INT64_MAX/INT64_MIN)。

double2fix64_z

int64_t double2fix64_z (double d, int e)

将双精度浮点数转换为给定小数位数的有符号 64 位定点整数,向零舍入。在 Arm 上,此转换对超出范围的输入是饱和的(到 INT64_MAX/INT64_MIN),但使用 pico_double compiler 时除外。

double2fix_z

int32_t double2fix_z (double d, int e)

将双精度浮点数转换为给定小数位数的有符号 32 位定点整数,向零舍入。在 Arm 上,此转换对超出范围的输入是饱和的(到 INT32_MAX/INT32_MIN),但使用 pico_double compiler 时除外。

double2int

int32_t double2int (double d)

将双精度浮点数转换为有符号 32 位整数,向负无穷舍入。此转换对超出范围的输入是饱和的(到 INT32_MAX/INT32_MIN)。

double2int64

int64_t double2int64 (double d)

将双精度浮点数转换为有符号 64 位整数,向负无穷舍入。此转换对超出范围的输入是饱和的(到 INT64_MAX/INT64_MIN)。

double2int64_z

int64_t double2int64_z (double d)

将双精度浮点数转换为有符号 64 位整数,向零舍入。在 Arm 上,此转换对超出范围的输入是饱和的(到 INT64_MAX/INT64_MIN),但使用 pico_double compiler 时除外。

double2int_z

int32_t double2int_z (double d)

将双精度浮点数转换为有符号 32 位整数,向零舍入。在 Arm 上,此转换对超出范围的输入是饱和的(到 INT32_MAX/INT32_MIN),但使用 pico_double compiler 时除外。

double2ufix

uint32_t double2ufix (double d, int e)

将双精度浮点数转换为给定小数位数的无符号 32 位定点整数,向负无穷舍入。此转换对超出范围的输入是饱和的(到 UINT32_MAX/UINT32_MIN)。

double2ufix64

uint64_t double2ufix64 (double d, int e)

将双精度浮点数转换为给定小数位数的无符号 64 位定点整数,向负无穷舍入。此转换对超出范围的输入是饱和的(到 UINT64_MAX/UINT64_MIN)。

double2ufix64_z

uint64_t double2ufix64_z (double d, int e)

将双精度浮点数转换为给定小数位数的无符号 64 位定点整数,向零舍入。此转换对超出范围的输入是饱和的(到 UINT64_MAX/UINT64_MIN)。

double2ufix_z

uint32_t double2ufix_z (double d, int e)

将双精度浮点数转换为给定小数位数的无符号 32 位定点整数,向零舍入。此转换对超出范围的输入是饱和的(到 UINT32_MAX/UINT32_MIN)。

double2uint

uint32_t double2uint (double d)

将双精度浮点数转换为无符号 32 位整数,向负无穷舍入。此转换对超出范围的输入是饱和的(到 UINT32_MAX/UINT32_MIN)。

double2uint64

uint64_t double2uint64 (double d)

将双精度浮点数转换为无符号 64 位整数,向负无穷舍入。此转换对超出范围的输入是饱和的(到 UINT64_MAX/UINT64_MIN)。

double2uint64_z

uint64_t double2uint64_z (double d)

将双精度浮点数转换为无符号 64 位整数,向零舍入。在 Arm 上,此转换对超出范围的输入是饱和的(到 UINT64_MAX/UINT64_MIN),但使用 pico_double compiler 时除外。

double2uint_z

uint32_t double2uint_z (double d)

将双精度浮点数转换为无符号 32 位整数,向零舍入。在 Arm 上,此转换对超出范围的输入是饱和的(到 UINT32_MAX/UINT32_MIN),但使用 pico_double compiler 时除外。

exp10

double exp10 (double x)

计算 10.0 的给定次幂。

fix2double

double fix2double (int32_t m, int e)

将给定小数位数的有符号 32 位定点整数转换为最近的双精度浮点数。超出范围的输入将转换为 +/- 无穷大。

fix642double

double fix642double (int64_t m, int e)

将给定小数位数的有符号 64 位定点整数转换为最近的双精度浮点数。超出范围的输入将转换为 +/- 无穷大。

fma_fast

double fma_fast (double x, double y, double z)

执行精度降低的快速(非融合)乘加(x * y + z)。

int2double

double int2double (int32_t i)

将有符号 32 位整数转换为最近的双精度浮点数。

int642double

double int642double (int64_t i)

将有符号 64 位整数转换为最近的双精度浮点数。

mla

double mla (double x, double y, double z)

执行精度降低的快速乘加(x * y + z)(非融合乘加)。这是 fma_fast 的另一个名称。

powint

double powint (double x, int32_t y)

将浮点数提升到整数幂。

sincos

void sincos (double x, double * sinx, double * cosx)

高效地返回一个角度的正弦和余弦值。

sqrt_fast

double sqrt_fast (double d)

执行精度降低的快速浮点平方根。

ufix2double

double ufix2double (uint32_t m, int e)

将给定小数位数的无符号 32 位定点整数转换为最近的双精度浮点数。超出范围的输入将转换为 +无穷大。

ufix642double

double ufix642double (uint64_t m, int e)

将给定小数位数的无符号 64 位定点整数转换为最近的双精度浮点数。超出范围的输入将转换为 +无穷大。

uint2double

double uint2double (uint32_t u)

将无符号 32 位整数转换为最近的双精度浮点数。

uint642double

double uint642double (uint64_t u)

将无符号 64 位整数转换为最近的双精度浮点数。


中文翻译版以英文版相同知识授权方式共享:CC-BY-SA 4.0。交流 Q群:498908352