我想知道进行逻辑右移是否更快,当将位移数设置为2的幂时。
例如,是否
myUnsigned >> 4
比任何更快
myUnsigned >> 3
我知道大家第一反应会告诉我不要担心这些微小的事情,使用正确的算法和集合来减少数量级才是最重要的。我完全同意你们的看法,但我真的在尝试挤出嵌入式芯片(ATMega328)的所有性能 - 我刚刚通过用位移替换除法获得了一个值得欢呼的性能提升,所以我向你保证这确实很重要。
我想知道进行逻辑右移是否更快,当将位移数设置为2的幂时。
例如,是否
myUnsigned >> 4
myUnsigned >> 3
我知道大家第一反应会告诉我不要担心这些微小的事情,使用正确的算法和集合来减少数量级才是最重要的。我完全同意你们的看法,但我真的在尝试挤出嵌入式芯片(ATMega328)的所有性能 - 我刚刚通过用位移替换除法获得了一个值得欢呼的性能提升,所以我向你保证这确实很重要。
我们来看看数据手册:
http://atmel.com/dyn/resources/prod_documents/8271S.pdf
就我所见,ASR(算术右移)总是向右移动一位,不能确定要移动的位数;它需要一个周期来执行。因此,向右移动 n 位将需要 n 个周期。二的幂与任何其他数字的行为都是相同的。
>> n
意味着编译器实际上会进行n个单独的asr
操作,我猜>>3
比>>4
快一点。事实上,ATMega没有移位寄存器,就像大多数(如果不是全部)其他8位MCU一样。因此,它每次只能向右移1位,而不是像更强大的CPU那样可以任意移位。因此,理论上移4位比移3位慢多了
然而,ATMega 确实有一个交换半字指令,所以实际上x >> 4
比x >> 3
更快
假设x
是一个uint8_t
,那么x >>= 3
由3次右移操作实现
x >>= 1;
x >>= 1;
x >>= 1;
而 x >>= 4
只需要进行一次交换和一次位清除操作。
swap(x); // swap the top and bottom nibbles AB <-> BA
x &= 0x0f;
或者
x &= 0xf0;
swap(x);
y0 = y1;
y1 = 0;
同样地,y >> 9
可以被优化为
y0 = y1 >> 1;
y1 = 0;
这里是编译器浏览器的一些演示
A right shift by 4 is achieved by a swap
and an and
like above
swap r24
andi r24,lo8(15)
A right shift by 3 has to be done with 3 instructions
lsr r24
lsr r24
lsr r24
左移操作也以相同方式进行了优化
另请参阅 哪个更快:x<<1还是x<<10?
对于这方面的信息,您需要查阅处理器文档。即使针对同一指令集,根据型号不同可能会有不同的成本。例如,在真正小的处理器上,向左或向右移动一个单位可能比其他值更快(例如,在某些IA32处理器上的旋转指令中情况就是如此,但这仅因为编译器极少生成此类指令)。
根据http://atmel.com/dyn/resources/prod_documents/8271S.pdf,ATMega328中所有逻辑移位都在一个周期内完成。但是,正如评论中指出的那样,所有逻辑移位都是每次移动一个位。因此,通过n
位移的成本是n
个周期和n
个指令。
Rd << 4
可以实现为SWAP Rd; ORI Rd, 0xF0
,并且比Rd << 3
更快。 - phuclv这取决于处理器的构建方式。如果处理器有一个桶旋转功能,它可以在一次操作中移动任意数量的位,但这需要芯片空间和功率预算。最经济实惠的硬件只能向右旋转一次,并具有关于环绕位的选项。下一个是可以左右旋转一次的处理器。我可以想象一个结构,其中包含1位移器、2位移器、4位移器等,这种情况下4可能比3更快。
恕我直言,在开始谈论性能之前,您应该先开始测量。使用除法编译程序。运行。测量时间。然后使用移位操作重复此过程。
char div2 (void)
{
return (-1) / 2;
// ldi r24,0
}
char asr1 (void)
{
return (-1) >> 1;
// ldi r24,-1
}
x >> 4
比x >> 3
更快?它们有不同的语义,因此哪个更快并不重要。无论如何,我从未遇到过任何一个体系结构,其中位移操作符的右操作数会对性能产生影响。 - fredoverflowx >> 4
和x >> 3
的区别 - 也许原帖作者在这方面有一些自由(例如进行定点算术并具有在小数部分有多大的余地) - Martin Bx >> 4
和x >> 3
之间切换。 - Niki