我正在做一个代码,其中在两个地方有64位乘32位定点除法,结果取32位。这两个地方在一起占用了我总时间的20%以上。所以我觉得如果我可以删除64位分区,我可以很好地优化代码。在NEON中,我们可以有一些64位指令。任何人都可以建议一些例行程序,通过使用一些更快的实现来解决瓶颈问题。针对ARM/NEON的64位/ 32位除法算法更快?
或者如果我可以在C中的32位/ 32位除法64位/ 32位除法,这也很好吗?
如果任何人有一些想法,你能帮我吗?
我正在做一个代码,其中在两个地方有64位乘32位定点除法,结果取32位。这两个地方在一起占用了我总时间的20%以上。所以我觉得如果我可以删除64位分区,我可以很好地优化代码。在NEON中,我们可以有一些64位指令。任何人都可以建议一些例行程序,通过使用一些更快的实现来解决瓶颈问题。针对ARM/NEON的64位/ 32位除法算法更快?
或者如果我可以在C中的32位/ 32位除法64位/ 32位除法,这也很好吗?
如果任何人有一些想法,你能帮我吗?
我在过去做了很多定点算术,并且做了大量的研究来寻找自己的64/32位快速分割。如果你的谷歌'ARM部门',你会发现吨伟大的联系和讨论这个问题。
为ARM架构,其中甚至有32位除法可能无法在硬件提供最好的解决办法是在这里:
http://www.peter-teichmann.de/adiv2e.html
这汇编代码是非常老了,你的汇编可能不理解它的语法。不过值得将代码移植到您的工具链中。这是迄今为止我见过的特殊情况下最快的分割代码,并且相信我:我已经将它们全部基准化了:-)
上次我做到了这一点(大约5年前,对于CortexA8)比编译器生成的速度快大约10倍。
此代码不使用NEON。一个NEON端口会很有趣。不知道它会不会提高性能。
编辑:
我发现汇编移植到GAS(GNU工具链)的代码。此代码的工作和测试:
Divide.S
.section ".text"
.global udiv64
udiv64:
adds r0,r0,r0
adc r1,r1,r1
.rept 31
cmp r1,r2
subcs r1,r1,r2
adcs r0,r0,r0
adc r1,r1,r1
.endr
cmp r1,r2
subcs r1,r1,r2
adcs r0,r0,r0
bx lr
C代码:
extern "C" uint32_t udiv64 (uint32_t a, uint32_t b, uint32_t c);
int32_t fixdiv24 (int32_t a, int32_t b)
/* calculate (a<<24)/b with 64 bit immediate result */
{
int q;
int sign = (a^b) < 0; /* different signs */
uint32_t l,h;
a = a<0 ? -a:a;
b = b<0 ? -b:b;
l = (a << 24);
h = (a >> 8);
q = udiv64 (l,h,b);
if (sign) q = -q;
return q;
}
语法真的很奇怪,但是如果我没有弄错,你链接的算法只是有条件地减去每个适合的除数(使用条件代码而不是分支)并保持一个计数。它是否正确?如果是这样,如果编译器体面,你可能可以在C中编写完全相同的东西并获得相同的性能。 – 2013-03-05 04:02:11
那么,*如果*编译器是体面的,你应该得到相同的结果。根据我的经验,只要您所做的每件事都是32位算术,ARM编译器就可以做得很好。只要你使用64位整数(在这里需要,因为你不能用C表达进位标志),它们会进入哑模式并产生不太好的代码。 – 2013-03-05 04:06:41
当'a'为-2147483648时,此代码失败。在这种情况下,'a a <0? -a:a;溢出。在常见的实现中,结果是-2147483648,然后'a >> 8'的结果是实现定义的,并且通常会导致错误的商被计算在后面。 – 2013-03-05 14:36:37
为什么票关闭? – 2013-03-05 03:43:53