algorithm - 简化/优化一段查看条件组合的代码的最佳方法是什么?

标签 algorithm optimization

我有一段代码想要优化以提高可读性、性能和酷炫度。现在我有这个丑陋的东西:

if      ( cond1 &&  cond2 &&  cond3 && !cond4)
{
     // do something 
}
else if ( cond1 &&  cond2 && !cond3 &&  cond4)
{
    // do something 
}
else if ( cond1 && !cond2 &&  cond3 &&  cond4)
{
   // do something 
}
else if (!cond1 &&  cond2 &&  cond3 &&  cond4)
{
    // do something 
}
else
{
    // do something 
}

其中 cond1cond2cond3cond4 是在 block 之前初始化的 bool 值上面的代码。我想让它更快、更不丑陋、更酷。

我正在考虑这样做:

int val = (cond1 ? 0 : 1) + 2 * (cond2 ? 0 : 1) + 4 * (cond3 ? 0 : 1) + 8 * (cond4 ? 0 : 1);
if (val == 8)
{
    // do something
}
else if (val == 4)
{
    // do something 
}
else if (val == 2)
{
    // do something
}
else if (val == 1)
{
    // do something
}
else
{
    // do something 
}

这行得通还是有缺陷?有没有更好的办法?在查看多种条件的不同组合时,实现预期结果的典型方法是什么?

最佳答案

您希望以一种或另一种方式将您的值放入位标志中。那就是你想要为每个条件设置或不设置整数类型。然后,您案例中的每个 4 位值都代表上述 ANDed 条件之一。之后,您可以使用 switch 语句。它可以说更具可读性,并且编译器通常可以将其优化为跳转表。也就是说,它只会将您的程序计数器偏移查找表中的某个值或类似的东西,您不再需要检查每个值的组合。通过这种方式,您对 ANDed 案例的检查变成了常数时间而不是线性的,也就是说,如果您再添加 4 个标志并且现在有 256 种组合而不是 16 种组合,那么这种方法将以大哦的方式同样快。或者,如果您不相信编译器会将 switch 语句设为跳转表,您可以使用 flags 值作为函数指针数组的索引自行完成。还可能值得注意的是,ORed 枚举大小写值在编译时被折叠或预先计算。

  enum {
    C1 = 0x1,
    C2 = 0x2,
    C3 = 0x4,
    C4 = 0x8
  };

  unsigned flags = 0;
  flags |= cond1 ? C1 : 0x0;
  flags |= cond2 ? C2 : 0x0;
  flags |= cond3 ? C3 : 0x0;
  flags |= cond4 ? C4 : 0x0;

  switch (flags) {
    case 0: // !cond1 && !cond2 && !cond3 && !cond4
      // do something
      break;
    case C1: //  cond1 && !cond2 && !cond3 && !cond4
      // do something
      break;
    case C2: // !cond1 &&  cond2 && !cond3 && !cond4
      // do something
      break;
    case C1 | C2: //  cond1 &&  cond2 && !cond3 && !cond4
      // do something
      break;
    case C3: // !cond1 && !cond2 &&  cond3 && !cond4
      // do something
      break;
    case C1 | C3: //  cond1 && !cond2 &&  cond3 && !cond4
      // do something
      break;
    case C2 | C3: // !cond1 &&  cond2 &&  cond3 && !cond4
      // do something
      break;
    case C1 | C2 | C3: //  cond1 &&  cond2 &&  cond3 && !cond4
      // do something
      break;
    case C4: // !cond1 && !cond2 && !cond3 &&  cond4
      // do something
      break;
    case C1 | C4: //  cond1 && !cond2 && !cond3 &&  cond4
      // do something
      break;
    case C2 | C4: // !cond1 &&  cond2 && !cond3 &&  cond4
      // do something
      break;
    case C1 | C2 | C4: //  cond1 &&  cond2 && !cond3 &&  cond4
      // do something
      break;
    case C3 | C4: // !cond1 && !cond2 &&  cond3 &&  cond4
      // do something
      break;
    case C1 | C3 | C4: //  cond1 && !cond2 &&  cond3 &&  cond4
      // do something
      break;
    case C2 | C3 | C4: // !cond1 &&  cond2 &&  cond3 &&  cond4
      // do something
      break;
    case C1 | C2 | C3 | C4: //  cond1 &&  cond2 &&  cond3 &&  cond4
      ; // do something
  };

此外,这涵盖了所有组合。如果您只需要一些子集,请随意删除一些案例。编译器非常擅长优化 switch 语句。它可能比您可以自己推出的任何聪明的特殊情况算术技巧都要快。

  enum {
    C1 = 0x1,
    C2 = 0x2,
    C3 = 0x4,
    C4 = 0x8
  };

  unsigned flags = 0;
  flags |= cond1 ? C1 : 0x0;
  flags |= cond2 ? C2 : 0x0;
  flags |= cond3 ? C3 : 0x0;
  flags |= cond4 ? C4 : 0x0;

  switch (flags) {
    case C1 | C2 | C3: //  cond1 &&  cond2 &&  cond3 && !cond4
      // do something
      break;
    case C1 | C2 | C4: //  cond1 &&  cond2 && !cond3 &&  cond4
      // do something
      break;
    case C1 | C3 | C4: //  cond1 && !cond2 &&  cond3 &&  cond4
      // do something
      break;
    case C2 | C3 | C4: // !cond1 &&  cond2 &&  cond3 &&  cond4
      // do something
      break;
    default:
      // do something
      ;
  };

关于algorithm - 简化/优化一段查看条件组合的代码的最佳方法是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23162309/

相关文章:

c++ - 我如何分析超出每个功能级别的代码?

algorithm - 从 n 个选择中有效地计算长度为 k 的下一个排列

c - 如何有效地在年历上存储任务信息

c++ - 对一组数字进行排列,然后将它们变成一个 int

javascript - 就时间优化而言,最好在 for 循环内部或外部声明 JavaScript 对象

c++ - 如何根据先前的行为预测系统的行为

algorithm - 如何高效地统计[start,end]之间质因数只有3或5的数字?

java - 碰撞分辨率 : Quadratic Probing vs. 单独链接

performance - 优化 "problems"在 libc 中的代码

c++ - 在插入之前使用 lower_bound 搜索 map 的好处。等同于 ptr_map?