qmath(3)
qmath — 基于 "Q" 数值格式的定点数学库
名称
qmath "Q" 数值格式
概要
#include <sys/qmath.h>
描述
qmath 数据类型和 API 支持基于"Q"数值格式的定点数学运算。这些 API 围绕以下数据类型构建:s8q_t、u8q_t、s16q_t、u16q_t、s32q_t、u32q_t、s64q_t 和 u64q_t,在先前的 API 定义中泛称为 QTYPE。ITYPE 指 stdint(7) 中的整数类型。NTYPE 用于指代任何数值类型,因此是 QTYPE 和 ITYPE 的超集。
该方案可以表示在小数点后具有 [2, 4, 6, 8, 16, 32, 48] 位精度的 Q 数,具体精度取决于 Q_INI() 的 rpshft 参数。可用于整数部分的位数没有显式指定,而是隐式占用所选 Q 数据类型的剩余可用位。
对 Q 数的操作保持其参数的精度。小数部分被截断以适应目标,不进行舍入。这些操作均不受浮点环境的影响。
有关更多细节,请参见下文的实现细节部分。
函数列表
创建/初始化 Q 数的函数
对两个 Q 数进行运算的数值函数
Q_QADDQ(3), Q_QDIVQ(3), Q_QMULQ(3), Q_QSUBQ(3), Q_NORMPREC(3), Q_QMAXQ(3), Q_QMINQ(3), Q_QCLONEQ(3), Q_QCPYVALQ(3)
将整数应用于 Q 数的数值函数
Q_QADDI(3), Q_QDIVI(3), Q_QMULI(3), Q_QSUBI(3), Q_QFRACI(3), Q_QCPYVALI(3)
对单个 Q 数进行运算的数值函数
Q_QABS(3), Q_Q2D(3), Q_Q2F(3)
比较与逻辑函数
Q_SIGNED(3), Q_LTZ(3), Q_PRECEQ(3), Q_QLTQ(3), Q_QLEQ(3), Q_QGTQ(3), Q_QGEQ(3), Q_QEQ(3), Q_QNEQ(3), Q_OFLOW(3), Q_RELPREC(3)
操作控制/符号数据位的函数
Q_SIGNSHFT(3), Q_SSIGN(3), Q_CRAWMASK(3), Q_SRAWMASK(3), Q_GCRAW(3), Q_GCVAL(3), Q_SCVAL(3)
操作组合整数/小数数据位的函数
Q_IFRAWMASK(3), Q_IFVALIMASK(3), Q_IFVALFMASK(3), Q_GIFRAW(3), Q_GIFABSVAL(3), Q_GIFVAL(3), Q_SIFVAL(3), Q_SIFVALS(3)
操作整数数据位的函数
Q_IRAWMASK(3), Q_GIRAW(3), Q_GIABSVAL(3), Q_GIVAL(3), Q_SIVAL(3)
操作小数数据位的函数
Q_FRAWMASK(3), Q_GFRAW(3), Q_GFABSVAL(3), Q_GFVAL(3), Q_SFVAL(3)
杂项函数/变量
Q_NCBITS(3), Q_BT(3), Q_TC(3), Q_NTBITS(3), Q_NFCBITS(3), Q_MAXNFBITS(3), Q_NFBITS(3), Q_NIBITS(3), Q_RPSHFT(3), Q_ABS(3), Q_MAXSTRLEN(3), Q_TOSTR(3), Q_SHL(3), Q_SHR(3), Q_DEBUG(3), Q_DFV2BFV(3)
实现细节
qmath 数据类型和 API 支持基于"Q"数值格式的定点数学运算。本实现使用 Q 表示法 Qm.n,其中 m 指定整数数据的位数(对于有符号类型不包括符号位),n 指定小数数据的位数。
这些 API 围绕以下从 q_t 派生的数据类型构建:
在先前的 API 定义中,这些类型被泛称为 QTYPE,而 ITYPE 指 Q 数据类型所派生自的 stdint(7) 整数类型。NTYPE 用于指代任何数值类型,因此是 QTYPE 和 ITYPE 的超集。
所有 q_t 数据类型的最低 3 位(LSB)保留用于嵌入式控制数据:
位 1-2 指定小数点移位索引操作数,00、01、10、11 分别对应 1、2、3、4。
位 3 指定小数点移位索引操作数的乘数为 2(0)或 16(1)。
因此,该方案可以表示在小数点后具有 [2, 4, 6, 8, 16, 32, 48, 64] 位精度的 Q 数。可用于整数部分的位数没有显式指定,而是隐式占用所选 Q 数据类型的剩余可用位。
此外,有符号 Q 类型的最高位(MSB)存储符号位,位值为 0 表示正数,位值为 1 表示负数。负数以设置了符号位的绝对值形式存储,而不是更常见的二进制补码表示。这避免了对负数进行位移操作,因为某些编译器可能导致未定义行为。
因此,用于 Q 数的二进制表示由一组不同的数据位类型和相关位计数组成。数据位类型/标签按从 LSB 到 MSB 的顺序列出为:控制位 'C'、小数位 'F'、整数位 'I' 和符号位 'S'。以下示例说明了使用 s32q_t 变量表示的 Q20.8 数的二进制表示:
重要的位计数包括:总位数、控制位、控制编码小数位、最大小数位、有效小数位和整数位。
总位数由 q_t 数据类型的大小决定。例如,s32q_t 有 32 个总位数。
控制编码小数位数通过按控制位编码方案计算小数位数得出。例如,控制位的二进制值 101 编码的小数位数为 2 × 16 = 32 位。
最大小数位数由总位数与控制/符号位数之差得出。例如,s32q_t 最多有 32 - 3 - 1 = 28 个小数位。
有效小数位数由控制编码小数位数和最大小数位数中的较小值决定。例如,具有 32 个控制编码小数位的 s32q_t 实际上被限制为 28 个小数位。
整数位数由总位数与所有其他非整数数据位(控制位、小数位和符号位之和)的差值得出。例如,具有 8 个有效小数位的 s32q_t 有 32 - 3 - 8 - 1 = 20 个整数位。如果所有可用的数值数据位都保留给小数数据,则整数位数可以为零,例如当控制编码小数位数大于或等于底层 Q 数据类型的最大小数位数时。
实例
计算 r=4.2、rpshft=16 时圆的面积
调试
声明一个 Q20.8 的 s32q_t 数 s32,用 5/3 的定点值初始化它,并将该变量的调试表示(包括其完整精度的十进制 C 字符串表示)渲染到控制台:
上述代码向控制台输出以下内容:
注意:上面渲染输出中的 "\n" 表示为使手册页保持在 80 列以内而手动插入的换行符,并非实际输出的一部分。
参见
errno(2), math(3), Q_FRAWMASK(3), Q_IFRAWMASK(3), Q_INI(3), Q_IRAWMASK(3), Q_QABS(3), Q_QADDI(3), Q_QADDQ(3), Q_SIGNED(3), Q_SIGNSHFT(3), stdint(7)
历史
qmath 函数首次出现于 FreeBSD 13.0。
作者
qmath 函数和本手册页由 Lawrence Stewart lstewart@FreeBSD.org 编写,由 Netflix, Inc. 赞助。
最后更新于
这有帮助吗?