如何避免在此操作中使用C分支

Daa*_*mer 7 c optimization performance

有没有办法删除以下if语句来检查该值是否低于0?

int a = 100;
int b = 200;
int c = a - b;

if (c < 0)
{
    c += 3600;
}
Run Code Online (Sandbox Code Playgroud)

c应在0和3600之间都撒谎ab签名.值a也应介于0和3600之间.(是的,它是0.1度的计数值).该值通过中断复位到3600,但如果该中断来得太晚,它会下溢,这不是问题,但软件应该仍然能够处理它.它做的.

我们if (c < 0)在相当一些计算位置的地方进行检查.(计算新职位等)

我曾经习惯使用模数运算符来使用除数的符号,我们的编译器(C89)正在使用除数签名.

有没有办法以不同的方式进行此计算?示例结果:

 a  -  b  = c
100 - 200 = 3500  
200 - 100 = 100
Run Code Online (Sandbox Code Playgroud)

jma*_*man 11

好问题!这个怎么样?

c += 3600 * (c < 0);
Run Code Online (Sandbox Code Playgroud)

这是我们保留分支预测器槽的一种方法.

  • @abelenky不,真值是零/非零,但比较运算符只返回零或一. (3认同)

zch*_*zch 7

这个怎么样(假设32位整数):

c += 3600 & (c >> 31);
Run Code Online (Sandbox Code Playgroud)

c >> 31 将所有位设置为原始MSB,对于负数,其为1,对于2-complement,其他为0.

负数移位权是根据C标准文档正式实现定义的,但它几乎总是用MSB复制实现(通用处理器可以在单个指令中完成).

这肯定会导致没有分支,(c < 0)在某些情况下可能会使用分支实现分支.


Jon*_*ler 5

你为什么担心这个分支?[原因在对该问题的评论中解释.]

替代方案如下:

((a - b) + 3600) % 3600
Run Code Online (Sandbox Code Playgroud)

这假定a并且b已经在范围内0..3600; 如果他们不受控制,更普遍的解决方案是Drew McGowen 建议:

((a - b) % 3600 + 3600) % 3600
Run Code Online (Sandbox Code Playgroud)

分支未命中必须非常昂贵才能使这么多计算变得有价值.