C++ 如何将一系列if/else if/else if/关系链转换为线性循环码

C++ 如何将一系列if/else if/else if/关系链转换为线性循环码,c++,vectorization,boolean-logic,boolean-expression,boolean-operations,C++,Vectorization,Boolean Logic,Boolean Expression,Boolean Operations,我有一个算法的核心,我想从一系列的if/else if/else if/else I/chain(大约20深)转换成一个可以以线性方式完成的循环。这些条件很简单,有4种可能性(A[i]=B[j])。如何将它们全部转换为单个条件。例如,链可以是这样的 if (A[i+0] < B[j+0]) break if (A[i+1] <= B[j+1]) break if (A[i+2] > B[j+2]) break if (A[i+3] >= B[j+3]) break i

我有一个算法的核心,我想从一系列的if/else if/else if/else I/chain(大约20深)转换成一个可以以线性方式完成的循环。这些条件很简单,有4种可能性(A[i]=B[j])。如何将它们全部转换为单个条件。例如,链可以是这样的

if (A[i+0] <  B[j+0]) break
if (A[i+1] <= B[j+1]) break
if (A[i+2] >  B[j+2]) break
if (A[i+3] >= B[j+3]) break
if (A[i+4] >= B[j+4]) break
....
if(A[i+0]=B[j+3])中断
如果(A[i+4]>=B[j+4])中断
....
每个条件可能是4个条件中的1个,但我想将它们全部转换为一组没有case的步骤,这样就可以在循环中完成(或者可能与向量内部函数并行)

//给定一个包含4个可能关系的列表R[n]循环所有数据
int结果=1;
对于(i=0;i=B[i];中断;
}
}
可以使用的(无符号数字)的某些属性包括

(A > B) ^ 1 === (A <= B) ^ 0
(A>B)^1==(A=B[i])&&(R[i]==3));
}
  • 创建符合签名的四个辅助函数:

    bool (*)(int A, int B);
    
    bool isLess(int A, int B) { return A < B; }
    bool isLessOrEqual(int A, int B) { return A <= B; }
    bool isGreater(int A, int B) { return A > B; }
    bool isGreaterOrEqual(int A, int B) { return A >= B; }
    
  • 使用循环中的函数数组

    for (i = 0; i < num_relations && result; ++i) {           
      result = functions[i](A[i], B[i]);
    }
    
    (i=0;i

  • 您可以使用按位

    result = 1;
    for (i = 0; i < num_relations && result; ++i) {           
        delta = A[i] - B[i];
    
        //  R[i] & 1 is true for 1 and 3
        //  R[i] & 2 is true for 2 and 3   
        if (delta == 0) {
            result = (R[i] & 1);
        }
        else  {
            //  exclusive or
            result = (delta < 0) ^ (R[i] & 2);
        }
    }
    
    result=1;
    对于(i=0;i

    诀窍是组合案例,从而减少关系操作的数量。

    如果不进行矢量化,您的
    if()
    序列将尽可能快。在这种情况下,每个条件必须有一条比较指令,您无法绕过它(即使有些机器可以优化分支,只有一条除外)

    使用矢量化,您可以并行执行多个比较,前提是它们都在同一个方向上。但这可以通过转换输入值来实现:

    int signs[] = {1, 1, -1, -1, -1, ...};
    int equals[] = {0, 1, 0, 1, 1, ...};
    if (A[i+0] <  signs[0]*B[j+0] + equals[0]) break;
    if (A[i+1] <  signs[1]*B[j+1] + equals[1]) break;
    if (A[i+2] <  signs[2]*B[j+2] + equals[2]) break;
    if (A[i+3] <  signs[3]*B[j+3] + equals[3]) break;
    if (A[i+4] <  signs[4]*B[j+4] + equals[4]) break;
    ...
    

    现在您可以自由地进行循环。

    通过函数指针进行调用是一项相当昂贵的操作。假设目标是性能,那么在这方面很难有所帮助。@Dashwuff,这是我今天学到的东西。你能提供一些我可以查阅的参考资料吗?谢谢。1个跳跃预测vs 4个分支预测。。。我会说函数指针赢。@Jarod42你错了。通过函数指针调用进行预测非常困难。许多处理器根本做不到这一点。我对实验非常开放,可以尝试一下,但正如所指出的,关键是性能和没有跳跃分支的直线代码。最终导致使用矢量化,这样就可以在N个关系中并行完成。这正是我正在寻找的魔法。不是说R[i]值及其映射到的关系可以针对逐位操作进行优化。我会检查这方面的数学知识,然后再给你回复我喜欢这一点,因为它有可能实现矢量化
    for (i = 0; i < num_relations && result; ++i) {           
      result = functions[i](A[i], B[i]);
    }
    
    result = 1;
    for (i = 0; i < num_relations && result; ++i) {           
        delta = A[i] - B[i];
    
        //  R[i] & 1 is true for 1 and 3
        //  R[i] & 2 is true for 2 and 3   
        if (delta == 0) {
            result = (R[i] & 1);
        }
        else  {
            //  exclusive or
            result = (delta < 0) ^ (R[i] & 2);
        }
    }
    
    int signs[] = {1, 1, -1, -1, -1, ...};
    int equals[] = {0, 1, 0, 1, 1, ...};
    if (A[i+0] <  signs[0]*B[j+0] + equals[0]) break;
    if (A[i+1] <  signs[1]*B[j+1] + equals[1]) break;
    if (A[i+2] <  signs[2]*B[j+2] + equals[2]) break;
    if (A[i+3] <  signs[3]*B[j+3] + equals[3]) break;
    if (A[i+4] <  signs[4]*B[j+4] + equals[4]) break;
    ...
    
    int signs[] = {1, 1, -1, -1, -1, ...};
    int equals[] = {0, 1, 0, 1, 1, ...};
    int doBreak = 0;
    doBreak |= (A[i+0] <  signs[0]*B[j+0] + equals[0]);
    doBreak |= (A[i+1] <  signs[1]*B[j+1] + equals[1]);
    doBreak |= (A[i+2] <  signs[2]*B[j+2] + equals[2]);
    doBreak |= (A[i+3] <  signs[3]*B[j+3] + equals[3]);
    doBreak |= (A[i+4] <  signs[4]*B[j+4] + equals[4]);
    ...
    if(doBreak) break;