15.16 数字的定点乘法/除法
我正在寻找一种算法来乘除定点 15.16 数字。
我已经有了加法和减法。这些都很简单——简单的 32 位加法和减法。通过乘法和除法,我还可以添加许多三角函数和指数/对数函数。我认为我可以只处理乘法,因为我的库有一个倒数函数,我可以用它来实现除法:a * (1/b) = a / b
。但 32 位乘法不起作用,因为它忽略小数点。
我正在开发 16 位微控制器,因此我想避免任何超过 32 位乘法的操作,这在我的处理器上大约需要 4 个周期。但这并不重要,我只是想替换浮点数学。
我听说我需要移动或旋转结果,但我不确定这将如何帮助或具体如何移动它。任何建议或帮助表示赞赏!
I am looking for an algorithm to multiply and divide fixed point 15.16 numbers.
I already have addition and subtraction. Those were easy - simple 32-bit add and subtract. With multiply and divide, I can also add many trigonometric and exponential/log functions. And I think I can deal with just multiply, as my library has a reciprocal function and I can use that to implement division: a * (1/b) = a / b
. But a 32-bit multiply does not work as it ignores the radix point.
I am working on a 16-bit microcontroller, so I would like to avoid anything more than 32-bit multiply, which takes about 4 cycles on my processor. It's not crucial though, I'm just trying to replace floating point math.
I have heard I need to shift or rotate the result, but I am not sure how this would help or specifically how to shift it. Any suggestions or help appreciated!
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
可以这样想:你的数字 ab 表示为 (ab * 65536)
如果你乘以 ab * cd,你得到的值是 (ab * 65536) * (cd * 65536),所以要把它放回正确的表示中需要除以 65536。
当您除 ab / cd 时,您得到的值为 (ab * 65536) / (cd * 65536),因此要将其放回正确的表示形式,您需要乘以 65536。您应该乘以 65536在除法之前保留结果中尽可能多的位。
当然,如果您的处理器速度更快,您可以用 (<< 16) 替换 (* 65536)。同样,您可以用 (>> 16) 替换 (/ 65536)。
这是 ab * cd:
Think of is this way: your number a.b is represented as (a.b * 65536)
If you multiply a.b * c.d the value you get is (a.b * 65536) * (c.d * 65536), so to put this back in the right representation you need to divide by 65536.
When you divide a.b / c.d the value you get is (a.b * 65536) / (c.d * 65536), so to put this back in the right representation you need to multiply by 65536. You should multiply by 65536 before the divide to preserve as many bits as possible in the result.
Of course you can substitute (<< 16) for (* 65536) if that is faster on your processor. Similarly you can substitute (>> 16) for (/ 65536).
Here's a.b * c.d:
首先是理论:假设有符号数,将 Q15.16 乘以另一个 Q15.16 将得到 Q(15+15+1).(16+16) = Q31.32 数。因此,您需要一个 64 位整数变量来保存结果。
如果您的编译器有 64 位整数类型,只需使用它并让编译器弄清楚如何在 16 位 CPU 上执行 32 位 x 32 位乘法(这就是编译器的用途)
: Q31.32 结果实际上取决于您的应用。
您可能想知道为什么结果需要 31 个整数而不是 30。事实上,只有在 -2^15 乘以 -2^15 的情况下才需要额外的位。如果保证您的操作数永远不会同时等于 -2^15,您可以假设 Q30.32 结果。
要了解您的编译器是否支持 64 位整数,您可能需要查看编译器手册。如果这是 C99 编译器,请查看 stdint.h 标头中是否有 int64_t 类型。
First the theory: assuming signed numbers, multiplying a Q15.16 by another Q15.16 will give you a Q(15+15+1).(16+16) = Q31.32 number. Thus, you need a 64-bit integer variable to hold the result.
If your compiler has a 64-bit integer type, just use it and let the compiler figure out how to do the 32-bit x 32-bit multiplication on the 16-bit CPU (that's what compilers are for):
What you do afterwards with the Q31.32 result really depends on your application.
You may be wondering why the result needs 31 integer instead of 30. In fact, the additional bit is needed only for the case where you multiply -2^15 by -2^15. If your operands are guaranteed never to equal -2^15 simultaneously, you can assume a Q30.32 result.
To find out if your compiler supports 64-bit integers, you may need to look at the compiler manual. If this is a C99 compiler, see if there is a int64_t type in your stdint.h header.
使用 64 位乘法可以轻松完成乘法:
(a * b) >>> 16.
.同样,除法也可以使用 64 位轻松完成:(a << 16) / b
。根据您的舍入/误差要求,您可能希望稍微复杂化,以便使输出的最后一位正确。The multiplication is easily done with 64-bit multiply:
(a * b) >> 16
. Division, similarly, is easily done with 64 bits:(a << 16) / b
. Depending on your rounding / error requirements, you might want to complicate that slightly in order to get the last bit of the output correct.