使用`lib_xcore_math`进行BFP运算
lib_xcore_math中的*_prepare()函数
为了方便BFP操作,lib_xcore_math的向量API中的许多函数都有一个相应的“准备”函数。通常,这个函数的名称是在原函数名称后面加上 _prepare。
例如,除了vect_s16_mul()之外,还有一个函数vect_s16_mul_prepare():
C_API
void vect_s16_mul_prepare(
exponent_t* a_exp,
right_shift_t* a_shr,
const exponent_t b_exp,
const exponent_t c_exp,
const headroom_t b_hr,
const headroom_t c_hr);
注意,vect_s16_mul_prepare()接受与向量b[]和c[]相关联的指数和头空间 ,但不直接接受b[]或c[]。准备函数的思想是利用可用的信息(除了实际输入元素值)来选择输出指数,并选择为函数所需的任何其他辅助输入参数。
在vect_s16_mul_prepare()的情况下,a_exp和a_shr是 输出 参数。输出指数通过a_exp输出,vect_s16_mul()所需的右移参数acc_shr通过a_shr输出。
与之相对比的是vect_s32_mul_prepare():
C_API
void vect_s32_mul_prepare(
exponent_t* a_exp,
right_shift_t* b_shr,
right_shift_t* c_shr,
const exponent_t b_exp,
const exponent_t c_exp,
const headroom_t b_hr,
const headroom_t c_hr);
该函数输出了两个移位参数b_shr和c_shr,这与vect_s32_mul()所需的参数相匹配。
最后,让我们来看一下vect_s32_dot_prepare(),我们将在第3B部分中遇到:
C_API
void vect_s32_dot_prepare(
exponent_t* a_exp,
right_shift_t* b_shr,
right_shift_t* c_shr,
const exponent_t b_exp,
const exponent_t c_exp,
const headroom_t b_hr,
const headroom_t c_hr,
const unsigned length);
除了接受一个length参数外,它与vect_s32_mul_prepare()非常相似。
而vect_s32_mul()对两个输入向量进行逐元素乘法运算,vect_s32_dot()则对逐元素乘积进行求和。因此,vect_s32_dot_prepare()还需要知道要求和的乘积数量。
如果正在将2个逐元素乘积相加,那么结果的可能值范围是元素乘积本身的两倍,这意味着指数需要增加以避免溢出。如果正在将16个逐元素乘积相加,结果可能会增大16倍,需要额外的4位()来存储结果,或者将输出指数增加4。
BFP类型
bfp_s32_t是lib_xcore_math中的一个结构类型,表示具有32位尾数的BFP向量。bfp_s32_t类型有4个重要字段:
| 字段 | 描述 |
|---|---|
int32_t* data | 指向int32_t数组的指针;用于支持尾数向量的缓冲区。 |
unsigned length | 表示BFP向量中元素的数量。 |
exponent_t exp | 与向量的尾数相关联的指数。 |
headroom_t hr | 向量尾数的头空间。 |
注意:在
lib_xcore_math中,除非另有说明,否则向量的“length”始终指元素的数量,而不是其欧几里得长度。
BFP操作
在第3部分的第3C部分中,我们将遇到几个BFP操作。
bfp_s32_init()
使用调用bfp_s32_init()来初始化bfp_s32_t(32位BFP向量)。最后一个参数calc_hr指示在初始化过程中是否计算头空间。当元素缓冲区未填充数据时,这是不必要的。
bfp_s32_dot()
bfp_s32_dot()计算两个BFP向量之间的内积,但与vect_s32_dot()不同,它会为我们处理所有指数和头空间的管理。bfp_s32_dot()基本上封装了第3B部分中执行的所有逻辑(除了将输出转换为适当的定点表示)。