以下两个代码序列产生相同的结果:
uint mod = val % 4;
uint mod1 = val & 0x3;
我可以用两者来计算相同的结果。我知道在硬件中&
运算符比%
运算符更简单。因此,我希望它的性能优于%
运算符。
我是否可以始终认为&
具有更好或相同的性能?
编译器会自动优化吗?
答案 0 :(得分:8)
你不能假设这些操作中的任何一个,编译可以优化两个相同的指令。
事实上,clang
和gcc
都会将它们转换为单个and
指令。
不幸的是,由于%
具有自ISO C99以来负值的指定返回值的性质,signed
整数需要一些额外的工作。与ISO C90相反,其中负模数是实现定义的。
两个操作的结果程序集,signed
和unsigned
值:
modulo
mov eax, DWORD PTR [esp+4] ; grab `val`
cdq ; convert 32-bit EAX to 64-bit
; and fill EDX with the sign bit
shr edx, 30 ; shift EDX by 30 positions to the right
; leaving only the two left-most bits
add eax, edx ; add EDX to EAX
and eax, 3 ; do the AND
sub eax, edx ; subtract EDX from EAX
mov DWORD PTR [esp+8], eax ; move result on stack
这是一个巧妙的技巧,为负值正确定义行为。它针对负值执行((val + 3) & 3) - 3
,针对正值执行val & 3
。
and
和未签名的modulo
mov eax, DWORD PTR [esp+4]
and eax, 3
mov DWORD PTR [esp+12], eax
答案 1 :(得分:1)
(现代)编译器应该从您的示例生成相同的代码,并且这种优化的原因是rhs是编译常量。
据我所知,&
运算符是用一个处理器指令and
完成的;模数运算符的情况并非如此,它通常意味着更多的运算(计算整数除法的余数)。 AFAIK,它通常比乘法长;我认为它只要是一个整数除法。