自修改代码vs编译器优化vs重复代码 我变得有点紧张,因为我不能使我的C++代码有效而不妥协。我开始写一些代码,如下所示 int foo(int a, int b, int c) { int result; bool cond1 = bar1(a, b, c); bool cond2 = bar2(a, b, c); bool cond3 = bar3(a, b, c); for (int i = 0; i < 10000; i++) { int start = 0; int end = 10000; if (cond1) start = max(start, baz1(i)); else start = max(start, baz2(i)); if (cond2) end = min(end, baz1(i)); else end = min(end, baz2(i)); for (int j = start; j < end; j++) { if (cond3) result += baz3(i, j); else result -= baz3(i, j); } } return result; } intfoo(inta,intb,intc) { int结果; bool cond1=bar1(a,b,c); bool cond2=bar2(a,b,c); bool cond3=bar3(a,b,c); 对于(int i=0;i

自修改代码vs编译器优化vs重复代码 我变得有点紧张,因为我不能使我的C++代码有效而不妥协。我开始写一些代码,如下所示 int foo(int a, int b, int c) { int result; bool cond1 = bar1(a, b, c); bool cond2 = bar2(a, b, c); bool cond3 = bar3(a, b, c); for (int i = 0; i < 10000; i++) { int start = 0; int end = 10000; if (cond1) start = max(start, baz1(i)); else start = max(start, baz2(i)); if (cond2) end = min(end, baz1(i)); else end = min(end, baz2(i)); for (int j = start; j < end; j++) { if (cond3) result += baz3(i, j); else result -= baz3(i, j); } } return result; } intfoo(inta,intb,intc) { int结果; bool cond1=bar1(a,b,c); bool cond2=bar2(a,b,c); bool cond3=bar3(a,b,c); 对于(int i=0;i,c++,C++,问题是,如何优化它,以避免在循环的每次迭代中检查条件“cond1,cond2,cond3”。我可以把内部循环写成 ... if (cond3) for (int j = start; j < end; j++) result += baz3(i, j); else for (int j = start; j < end; j++) result -= baz3(i, j);

问题是,如何优化它,以避免在循环的每次迭代中检查条件“cond1,cond2,cond3”。我可以把内部循环写成

...
        if (cond3)
        for (int j = start; j < end; j++)
            result += baz3(i, j);
        else
        for (int j = start; j < end; j++)
            result -= baz3(i, j);

...
。。。
如果(第3条)
对于(int j=开始;j<结束;j++)
结果+=baz3(i,j);
其他的
对于(int j=开始;j<结束;j++)
结果-=baz3(i,j);
...
这将“cond3”的检查次数从10000次减少到10000次。但是仍然有29997个冗余检查,为了优化它,我只看到复制循环2^3=8次的选项。由于循环与条件的指数增长,我有一些问题:

  • 我可以依靠编译器优化器来展开循环吗
  • 反对自修改代码的理由是什么,因为在这种情况下,不仅会减少程序大小,而且代码也更易于管理。我发现很难相信,自从C++被发明以来,上面还没有遇到过这样的问题。

  • 函数指针。使用函数指针。
    使用3个函数指针,每个条件一个

    例如:

      Function_Pointer_Type_Cond1 p_cond_1_function;
      Function_Pointer_Type_Cond2 p_cond_2_function;
      if (bar1(a, b, c))
      {
        p_cond_1_function = baz1;
      }
      else
      {
        p_cond_1_function = baz2;
      }
      if (bar2(a, b, c))
      {
        p_cond_2_function = baz1;
      }
      else
      {
        p_cond_2_function = baz2;
      }
      for (int i = 0; i < 10000; i++)
      {
        int start = 0;
        int end = 10000;
        start = max(start, (*p_cond_1_function)(i));
        end   = min(end,   (*p_cond_2_function)(i));
        // ...
      }
    
    Function\u Pointer\u Type\u Cond1 p\u Cond1\u Function;
    函数(指针)类型(Cond2 p)Cond2(函数);;
    if(bar1(a,b,c))
    {
    p_cond_1_函数=baz1;
    }
    其他的
    {
    p_cond_1_函数=baz2;
    }
    if(bar2(a,b,c))
    {
    p_cond_2_函数=baz1;
    }
    其他的
    {
    p_cond_2_函数=baz2;
    }
    对于(int i=0;i<10000;i++)
    {
    int start=0;
    int end=10000;
    开始=最大值(开始,(*p_cond_1_函数)(i));
    end=min(end,(*p_cond_2_函数)(i));
    // ...
    }
    
    使用函数指针可以删除“if”语句。由于函数在
    for
    循环中不会更改,因此可以在循环之前指定函数指针

    有关函数指针的详细信息,请在web上搜索“C++常见问题解答函数指针”,或在StackOverflow中搜索“C++函数指针”

    释放压力

    做一些基准测试,但我的预测是,您的代码很好,因为即使是最简单的分支预测形式,它也会使所有这些测试几乎免费,而且肯定比函数调用便宜,更不用说间接函数调用了


    如果baz1和baz2很简单,请确保它们可以内联。如果它们不是微不足道的,那么几乎总是成功预测的分支是无关紧要的。

    如果,您可以轻松删除第三个


    只要总是在循环内做加法,在循环结束后,在返回之前,对结果求反,如果cond3是这样指出的。

    你看过任何编译器的输出代码吗?反对自修改代码的论点大概在40年前就有了很好的阐述——这使得代码有缺陷且效率低下。如果编译器能够确定
    cond1
    cond2
    cond3
    在循环体中是不变的,它可能会在高优化级别上优化它的垃圾。但目前的代码设计得很糟糕。您需要性能、可移植性还是可维护性?选择任意两个。您最多有8个变体。如果您非常担心性能,您可以编写整个例程的8个独立版本,并选择执行哪个版本。在某种程度上,它比所有的if测试都不那么晦涩。不,我没有看编译器的输出代码。我已经读到过级别-O3展开循环,但我对此表示怀疑,因为在这个例子中,版本的数量是指数级的。代码如何变得有缺陷和低效?我只看到更多可维护和小规模的代码,并在必要时编写8个不同版本的例程。至于性能、可移植性和可维护性,Java在运行时不是或者应该能够获得这样的效率吗?嗯,也许我没有告诉你,“baz”函数也可以是内联的,它们是三个算术运算,因此完整的调用过程比“if”更低效检查。@user2275809如果不进行测量,很难明确指出函数调用比测试和分支更昂贵。@user2275809 lambda不是有效的本地内联函数吗(如果编译器认为它们符合条件)?