按位运算符更快吗?如果是,那为什么呢?
Are bitwise operators faster?, if yes then why?
如果我使用它会对性能有多大影响:
n>>1 instead of n/2
n&1 instead of n%2!=0
n<<3 instead of n*8
n++ instead of n+=1
and so on...
如果它确实提高了性能,请解释原因。
严格来说,在大多数情况下,是的。
这是因为 APU 中的电路更简单并且需要更少的离散步骤(时钟周期)才能完全执行,因此对于 CPU 来说,位操作是一种更简单的操作。
正如其他人所提到的,任何值得一提的编译器都会自动检测某些算术运算的常量操作数(如您示例中的那些),并将它们转换为适当的位运算。
请记住,如果操作数是运行时值,则无法进行此类优化。
任何半正经的编译器都会将这两个版本优化成相同的东西。例如,GCC 编译这个:
unsigned int half1(unsigned int n) { return n / 2; }
unsigned int half2(unsigned int n) { return n >> 1; }
bool parity1(int n) { return n % 2; }
bool parity2(int n) { return n & 1; }
int mult1(int n) { return n * 8; }
int mult2(int n) { return n << 3; }
void inc1(int& n) { n += 1; }
void inc2(int& n) { n++; }
至
half1(unsigned int):
mov eax, edi
shr eax
ret
half2(unsigned int):
mov eax, edi
shr eax
ret
parity1(int):
mov eax, edi
and eax, 1
ret
parity2(int):
mov eax, edi
and eax, 1
ret
mult1(int):
lea eax, [0+rdi*8]
ret
mult2(int):
lea eax, [0+rdi*8]
ret
inc1(int&):
add DWORD PTR [rdi], 1
ret
inc2(int&):
add DWORD PTR [rdi], 1
ret
一个小警告是,在第一个例子中,如果 n
可能是负数(如果它是有符号的并且编译器不能证明它是非负数),那么除法和位移是不等同,该部门需要一些额外的说明。除此之外,编译器很聪明,它们会使用常量操作数优化操作,因此请使用逻辑上更有意义且更具可读性的版本。
如果我使用它会对性能有多大影响:
n>>1 instead of n/2
n&1 instead of n%2!=0
n<<3 instead of n*8
n++ instead of n+=1
and so on...
如果它确实提高了性能,请解释原因。
严格来说,在大多数情况下,是的。
这是因为 APU 中的电路更简单并且需要更少的离散步骤(时钟周期)才能完全执行,因此对于 CPU 来说,位操作是一种更简单的操作。
正如其他人所提到的,任何值得一提的编译器都会自动检测某些算术运算的常量操作数(如您示例中的那些),并将它们转换为适当的位运算。
请记住,如果操作数是运行时值,则无法进行此类优化。
任何半正经的编译器都会将这两个版本优化成相同的东西。例如,GCC 编译这个:
unsigned int half1(unsigned int n) { return n / 2; }
unsigned int half2(unsigned int n) { return n >> 1; }
bool parity1(int n) { return n % 2; }
bool parity2(int n) { return n & 1; }
int mult1(int n) { return n * 8; }
int mult2(int n) { return n << 3; }
void inc1(int& n) { n += 1; }
void inc2(int& n) { n++; }
至
half1(unsigned int):
mov eax, edi
shr eax
ret
half2(unsigned int):
mov eax, edi
shr eax
ret
parity1(int):
mov eax, edi
and eax, 1
ret
parity2(int):
mov eax, edi
and eax, 1
ret
mult1(int):
lea eax, [0+rdi*8]
ret
mult2(int):
lea eax, [0+rdi*8]
ret
inc1(int&):
add DWORD PTR [rdi], 1
ret
inc2(int&):
add DWORD PTR [rdi], 1
ret
一个小警告是,在第一个例子中,如果 n
可能是负数(如果它是有符号的并且编译器不能证明它是非负数),那么除法和位移是不等同,该部门需要一些额外的说明。除此之外,编译器很聪明,它们会使用常量操作数优化操作,因此请使用逻辑上更有意义且更具可读性的版本。