0

我正在寻找一种算法来乘除定点 15.16 数字。

我已经有加减法了。这些很简单——简单的 32 位加减法。通过乘法和除法,我还可以添加许多三角函数和指数/对数函数。而且我想我可以只处理乘法,因为我的库有一个倒数函数,我可以用它来实现除法:a * (1/b) = a / b. 但是 32 位乘法不起作用,因为它忽略了小数点。

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

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

4

3 回答 3

5

想想是这样的:你的数字ab表示为(ab * 65536)

如果将 ab * cd 相乘,得到的值为 (ab * 65536) * (cd * 65536),因此要将其放回正确的表示中,您需要除以 65536。

当您除以 ab / cd 时,您得到的值为 (ab * 65536) / (cd * 65536),因此要将其放回正确的表示中,您需要乘以 65536。您应该在除法之前乘以 65536 以保留为结果中尽可能多的位。

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

这是 ab * cd:

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)
于 2011-01-22T18:30:58.087 回答
2

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

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

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 类型。

于 2011-01-23T20:36:30.733 回答
0

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

于 2011-01-22T18:27:03.930 回答