C中的不平等更快

时间:2013-11-23 23:04:30

标签: c performance optimization if-statement inequality

让我们说我们有这些不平等:

if (a*a+b*b>0) {
    ...
}

if (a*b+c*d>0) {
    ...
}

显然,它们都需要2次乘法来评估 问题是,我们真的需要计算2个全精度产品才能检查这些表达是否为正? 是否有任何数学技巧可以让我在不需要评估2个产品的情况下编写命令? 它会更快吗?
或者编译器可能会尽可能快地完成它? 我是否在思考?

编辑: 嗯,这很快就升级了。 我只是想指出一般的说法。无论如何,我在任何项目中都不需要这样的微优化。 还有,是的,我可以省略第一个因为太琐碎。可能第二个更有趣。

4 个答案:

答案 0 :(得分:2)

你的“我是否过度思考”这个问题告诉我,你没有通过真正分析代码来发现这是一个真正的瓶颈。所以我会说是的,你只是想做一个过早的优化。

然而,如果这确实是您的应用程序的主要性能关键部分,那么我现在能想到的唯一改进如下。由于实数的平方永远不会是负数,因此“平方大于零”等同于“a不为零”。因此,如果您的架构上的比较很快(嗯,那是相对的 - 比乘法更快),那么

if (a*a+b*b>0) {
    ...
}

可以写成

if (a || b) {
    ...
}

(假设没有出现转角情况。如果变量是有符号整数或表示实数的浮点数,那么这应该没问题。但是,如果有一些无符号整数溢出或涉及复数,那么你将必须执行额外的检查,此时,如果没有真正的分析,很难推断相对性能。)

对于我脑海中的第二个案例,我没有这样一个“聪明”的“优化”,但也许其他人可以提出类似的东西 - 当且仅当它是绝对必要的。 否则 - 当性能不重要时,代码可读性优于性能。

答案 1 :(得分:1)

我假设这些表达式都不会溢出,因为类型没有溢出的概念或因为值在范围内。当溢出和潜在的环绕进入图片时(例如,如果abunsigned int),则适用不同的规则。

第一个陈述显然等同于

if (a != 0 || b != 0)

if (a || b)

交换额外的分支进行两次乘法和加法。

第二个陈述更有趣:我认为确定操作数的符号是​​合理的,只有当a*bc*d具有相反符号时才进行实际数学运算。在所有其他情况下,可以在不知道实际值的情况下确定条件。结果逻辑是否比计算更快将取决于类型,我猜。

答案 2 :(得分:1)

第一个将始终为> = 0.当且且仅当ab为0时,它将为0,因此它等同于:

if (a || b) {
   ...
}

关于第二个问题:如果a的符号等于b的符号,并且c的符号等于d的符号,那么它就是&#39 ;与上述情况相同:

if (sign(a)==sign(b) && sign(c)==sign(d))
{
  if ((a && b) || (c && d))
  {
    ... > 0
  }
  else
  {
    ... = 0
  }
}
else
{
  if (sign(a)*sign(b)==sign(c)*sign(d))
  {
     ... <= 0
  }
  else
  {
    /* must do the actual product to find out */
  }
}

对于符合IEEE-754标准的浮点数,符号位于每个数字的MSb处。

对于模拟FP的环境,您可以做一件事来优化比较:如果您只是比较产品的两个结果,您可以避免添加:

if (a*b>c*d) {
   ...
}

这有点快,因为要比较两个浮点数,你只需比较它们就像它们是有符号整数一样,而无FP的CPU肯定会有资源来比它花费的时间更快地比较两个整数FP软件的补充。

答案 3 :(得分:0)

另一个重写(假设您正在使用浮点数,它们符合32 bits wide and IEEE 754,并且与int的大小相同;是的,这是hacky和平台相关的)。

对于第一种情况,您可以使用单个按位'或'&amp; '和'(用于忽略符号位和指数,仅保留尾数;如果不能有任何-0,则可以删除它):

if (*((int *)&a) | (*(int *)&b) & 0x7FFFFF) { // a*a + b*b>0
  ...
}

我真的怀疑第二种情况下没有任何类似的无分支魔法。