Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/160.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 在特殊情况下:Is&;快于%?_C++_C_Performance - Fatal编程技术网

C++ 在特殊情况下:Is&;快于%?

C++ 在特殊情况下:Is&;快于%?,c++,c,performance,C++,C,Performance,我看到了被选中的人 我很惊讶(x&255)==(x%256)如果x是一个无符号整数,我想知道在x%n中总是用和替换%是否有意义,因为n=2^a(a=[1,…])和x是一个正整数 因为这是一种特殊情况,我作为一个人可以决定,因为我知道程序将处理哪些值,而编译器不知道如果我的程序使用了大量的模运算,我能否获得显著的性能提升? 当然,我可以编译并查看disassembly。但这只能回答我关于一个编译器/体系结构的问题。我想知道这在原则上是否更快。如果整数类型是无符号的,编译器将对其进行优化,结果将是相

我看到了被选中的人

我很惊讶
(x&255)==(x%256)
如果x是一个无符号整数,我想知道在
x%n
中总是用
替换
%
是否有意义,因为
n=2^a(a=[1,…])
和x是一个正整数

因为这是一种特殊情况,我作为一个人可以决定,因为我知道程序将处理哪些值,而编译器不知道如果我的程序使用了大量的模运算,我能否获得显著的性能提升?


当然,我可以编译并查看disassembly。但这只能回答我关于一个编译器/体系结构的问题。我想知道这在原则上是否更快。

如果整数类型是无符号的,编译器将对其进行优化,结果将是相同的。如果签了名,事情就不一样了

该计划:

int mod_signed(int i) {
  return i % 256;
}
int and_signed(int i) {
  return i & 255;
}
unsigned mod_unsigned(unsigned int i) {
  return i % 256;
}
unsigned and_unsigned(unsigned int i) {
  return i & 255;
}
将()编译为:

mod_signed
的结果程序集不同,因为

如果乘法、除法或模表达式的两个操作数具有相同的符号,则结果为正。否则,结果是否定的。模运算符号的结果由实现定义

在AFAICT中,大多数实现决定模表达式的结果始终与第一个操作数的符号相同。看

因此,
mod_signed
优化为(from的注释):

intd=i<0?255 : 0;
返回((i+d)&255)-d;


从逻辑上讲,我们可以证明所有无符号整数的
i%256==i&255
,因此,我们可以信任编译器来完成它的工作。

我用gcc做了一些测量,并且 如果
/
%
的参数是一个2次方的编译时间常数,gcc可以将其转换为相应的位运算

以下是我对部门的一些基准 正如您所看到的,使用静态已知的二次幂的除数的运行时间明显低于使用其他静态已知的除数的运行时间

因此,如果两个参数的静态已知幂的
/
%
比位运算更好地描述了您的算法,请随意选择
/
%

有了一个像样的编译器,你不应该失去任何性能。

你的意思是
x&255==x%256
。对于无符号算术,任何称职的编译器都会为两者生成相同的代码。永远不要编写“优化”代码。编写反映您想要做什么的代码,编译器优化将完成它们的工作。编写这样的代码会降低可读性、可移植性,并经常破坏编译器的优化。你的博士朋友听起来像是一个从不需要在团队中编写代码并维护代码的人long@Felk,另一个经验法则是先获得正确的代码,然后再进行优化。当代码不清晰时就更难了。正如您所看到的,这对性能应该没有影响。就我个人而言,我通常更喜欢按位,对我来说,立即可视化被截断的位字符串比考虑模运算更容易,记住余数的二次方是一个特殊的好例子,我可以再次可视化为被截断的位字符串。如果它是有符号的,不同之处在于,
n
不是静态的,编译器无法对其进行优化though@Jonas修正了typo@Felk如果我们不知道它的静态,我们不能改变它的位和虽然!如果我们选择比较和分支,我认为这对任何好奇的人都不好,为
mod_signed
生成的代码相当于:
int d=I<0?255 : 0; 返回((i+d)&255)-d对于/和%,这仅在未签名的情况下为真。您不会损失太多性能,但实现2的等幂有符号除法需要的不仅仅是算术右移(处理负数舍入的差异)。类似地,在有符号整数上使用div或mod的非2次幂的模乘逆也需要额外的工作。@PeterCordes然而,编译器足够聪明,知道“(a%b+b)%b”,并且可以转换为位运算。我还没有找到一个可以将除法转换为移位的优化表达式。@Random832:我的意思是用编译时常量除法。
mod_signed(int):
        mov     edx, edi
        sar     edx, 31
        shr     edx, 24
        lea     eax, [rdi+rdx]
        movzx   eax, al
        sub     eax, edx
        ret
and_signed(int):
        movzx   eax, dil
        ret
mod_unsigned(unsigned int):
        movzx   eax, dil
        ret
and_unsigned(unsigned int):
        movzx   eax, dil
        ret
int d = i < 0 ? 255 : 0;
return ((i + d) & 255) - d;