固定点乘以/除以15.16的数字

时间:2011-01-22 18:22:57

标签: fixed-point

我正在寻找一种算法来乘以和除以15.16的固定点数。

我已经有加法和减法。那些很简单 - 简单的32位加法和减法。通过乘法和除法,我还可以添加许多三角函数和指数/日志函数。我认为我可以处理多次,因为我的库有一个互惠函数,我可以用它来实现除法:a * (1/b) = a / b。但是32位乘法不起作用,因为它忽略了小数点。

我正在研究一个16位微控制器,所以我想避免超过32位乘法,这在我的处理器上需要大约4个周期。但这并不重要,我只是想替换浮点数学。

我听说我需要移动或旋转结果,但我不确定这将如何帮助或具体如何移动它。任何建议或帮助表示赞赏!

3 个答案:

答案 0 :(得分:5)

想一想:你的号码a.b表示为(a.b * 65536)

如果你乘以a.b * c.d,你得到的值是(a.b * 65536)*(c.d * 65536),所以要把它放回到正确的表示中,你需要除以65536.

当你划分ab / cd时,得到的值是(ab * 65536)/(cd * 65536),所以要把它放回到正确的表示中,你需要乘以65536.你应该在除以前乘以65536在结果中保留尽可能多的位。

当然,如果处理器上的速度更快,您可以用(<< 16)代替(* 65536)。同样,您可以将(>> 16)替换为(/ 65536)。

这是a.b * c.d:

uint32_t result_low = (b * d);
uint32_t result_mid = (a * d) + (b * c);
uint32_t result_high = (a * c); 
uint32_t result = (result_high << 16) + result_mid + (result_low >> 16)

答案 1 :(得分:2)

首先理论:假设有符号数,将Q15.16乘以另一个Q15.16将得到Q(15 + 15 + 1)。(16 + 16)= Q31.32数。因此,您需要一个64位整数变量来保存结果。

如果您的编译器具有64位整数类型,只需使用它并让编译器弄清楚如何在16位CPU上执行32位x 32位乘法(这就是编译器的用途):< / p>

int32_t a_15q16, b_15q16;
int64_t res_31q32 = (int64_t)a_15q16 * (int64_t)b_15q16;

之后使用Q31.32结果所做的事情取决于您的应用程序。

您可能想知道为什么结果需要31个整数而不是30个。实际上,只有在将-2 ^ 15乘以-2 ^ 15的情况下才需要附加位。如果保证操作数不会同时等于-2 ^ 15,则可以假设Q30.32结果。

要了解您的编译器是否支持64位整数,您可能需要查看编译器手册。如果这是一个C99编译器,请查看stdint.h头文件中是否有int64_t类型。

答案 2 :(得分:0)

乘法很容易用64位乘法运算:(a * b) >> 16。类似地,分区很容易用64位完成:(a << 16) / b。根据您的舍入/错误要求,您可能希望稍微复杂一点,以使输出的最后一位正确。