繁体   English   中英

大多数编译器是否将%2转换为比特? 真的更快吗?

[英]Do most compilers transform % 2 into bit comparison? Is it really faster?

在编程中,通常需要检查数字是奇数还是偶数。 为此,我们通常使用:

n % 2 == 0

但是,我的理解是'%'运算符实际执行除法并返回其余数; 因此,对于上述情况,简单地检查最后一位会更快。 比方说n = 5;

5 = 00000101

为了检查数字是奇数还是偶数,我们只需要检查最后一位。 如果是1 ,那么数字是奇数; 否则,它是均匀的。 在编程中,它将表达如下:

n & 1 == 0

根据我的理解,这将比% 2更快,因为没有执行除法。 需要进行一点比较。

那我有2个问题:

1)第二种方式是否真的比第一种方式快(在所有情况下)?

2)如果1的答案是肯定的,编译器(所有语言)是否足够智能将% 2转换为简单的比特? 或者,如果我们想要最佳性能,我们是否必须明确使用第二种方式?

是的,比特测试比整数除法快得多由约10倍至20,或甚至100为128位/ 64位的64位= IDIV英特尔 ESP。 因为x86至少有一个test指令,它根据按位AND的结果设置条件标志,所以你不必进行除法然后比较; 按位AND 比较。

我决定实际检查Godbolt上的编译器输出 ,并得到一个惊喜:

事实证明,使用n % 2作为有符号整数值(例如,从返回signed int的函数return n % 2 )而不是仅仅测试非零( if (n % 2) )有时会产生比return n & 1 这是因为(-1 % 2) == -1 ,而(-1 & 1) == 1 ,所以编译器不能使用按位AND。 编译器仍然避免整数除法,而是使用一些聪明的shift /和/ add / sub序列,因为它仍然比整数除法便宜。 (gcc和clang使用不同的序列。)

因此,如果您想基于n % 2返回真值,那么您最好的选择是使用无符号类型。 这使编译器始终可以将其优化为单个AND指令。 (在godbolt上,您可以转到其他体系结构,如ARM和PowerPC,并看到unsigned even% )函数和int even_bit (按位& )函数具有相同的asm代码。)

使用bool (必须是0或1,而不仅仅是任何非零值)是另一种选择,但编译器必须做额外的工作才能返回(bool) (n % 4) (或者除了n%2之外的任何测试(bool) (n % 4) n%2 )。 它的按位和版本将为0,1,2或3,因此编译器必须将任何非零值转换为1.(x86具有有效的setcc指令,将寄存器设置为0或1,具体取决于在标志,所以它仍然只有2条指令,而不是1铛/ GCC使用这个,看aligned4_bool在godbolt ASM输出)。

如果任何优化级别高于-O0 ,则gcc和clang将if (n%2)优化为我们期望的值。 另一个巨大的惊喜是icc 13 没有 我不明白WTF icc认为它正在对所有这些分支做

速度相当。

无论实现语言如何,模数版本通常都能保证整数是正数,负数还是零。 按位版本不是。

使用您认为最具可读性的内容。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM