是否有办法计算:
/** clipped(a - b) **/
unsigned char clipped_substract(unsigned char a, unsigned char b)
{
return a > b ? a - b : 0;
}使用一些二进制操作而不是测试?
发布于 2019-12-13 11:39:55
/** clipped(a - b) **/
unsigned char clipped_substract(unsigned char a, unsigned char b)
{
return a - (a+b) / 2 + getAbs(a-b) / 2;
}
unsigned int getAbs(int n)
{
int const mask = n >> (sizeof(int) * 8 - 1);
return ((n + mask) ^ mask);
}发布于 2019-12-13 12:14:22
原始函数编译为条件移动,不受性能问题的影响。您正在尝试在这里执行过早优化,这对您绝对没有好处。编写可读的代码,然后分析它,然后识别和优化性能瓶颈。
你说“测试可以降低性能”。如果你想做这样的微观优化,你应该把目标放在理解这些经验法则背后的原因,而不是把它们作为无条件的真理。
降低“测试”性能的是(错误预测)控制流分支。现代CPU大量使用指令流水线,控制流分支意味着不清楚下一步是哪个指令。通常的方法是CPU猜测(使用分支预测硬件/算法)分支的方向。如果它弄错了,它必须冲洗整个管道,并重新填充它,这浪费了循环。
嗯,有关的代码没有这样的问题。它编译成一个有条件的移动:
clipped_substract(unsigned char, unsigned char):
mov eax, edi
mov edx, 0
sub eax, esi
cmp dil, sil
cmovbe eax, edx
ret您可以看到这里没有控制流分支。有关不受上述性能问题影响的原因,请参见为什么有条件的移动不容易导致分支预测失败?。
重复一遍:编写可读的代码,然后分析它,然后识别和优化性能瓶颈。这里您尝试的是修复一段根本不存在的性能问题代码(更不用说您没有证明该代码的性能甚至与程序的性能相关)。
发布于 2019-12-13 12:26:56
使用clang 11.0,编译器优化启用
unsigned char clipped_substract(unsigned char a, unsigned char b)
{
long c = b - a;
return ((unsigned long)c >> (sizeof(c)*8-1)) * c;
}尽管任何替代方案所花费的时间都会被忽略地不同,但是在执行10000000迭代时,其他方法在我的机器上占用0.300secs,而这个解决方案需要0.200secs。
但是,只有当您使用一个大小大于char的类型时,这才是有效的,例如,这里我使用了long。我不记得char或long的确切定义,但我知道在我的机器上long比char更广泛。因此,相应地调整它。
基本上,我只是把减法的结果存储在一个更大的宽度变量中。如果结果为负值,则最重要的位将是1 else 0。
https://stackoverflow.com/questions/59321713
复制相似问题