Playing around with removing branches in C++, unable to decipher reasoning behind output.
PopHi() takes two vectors of ascending sorted ints and the current index of the greatest in each so far. It ‘pops’ the greatest int of all by decrementing index of the greater of the two.
Code
Original:
void PopHi(vector<int> &arrA, vector<int> &arrB, int &idxHiA, int &idxHiB) {
int hi = max(arrA[idxHiA], arrB[idxHiB]);
if (hi == arrA[idxHiA])
--idxHiA;
else
--idxHiB;
}
Nobranch version 1:
void PopHi(vector<int> &arrA, vector<int> &arrB, int &idxHiA, int &idxHiB) {
idxHiA -= (arrA[idxHiA] > arrB[idxHiB]);
idxHiB -= (!(arrA[idxHiA] > arrB[idxHiB]));
}
Nobranch version 2, since it shouldn’t matter which one we pick if they’re equal:
void PopHi(vector<int> &arrA, vector<int> &arrB, int &idxHiA, int &idxHiB) {
idxHiA -= (arrA[idxHiA] >= arrB[idxHiB]);
idxHiB -= (!(arrA[idxHiA] >= arrB[idxHiB])); // extra paranoia parens
}
And this is how I’m using it:
// compiled with g++ -std=c++11 main.cpp -o run
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
int main() {
vector<int> arrA({1, 3, 5});
vector<int> arrB({5});
int idxHiA = 2;
int idxHiB = 0;
cout << idxHiA << ", " << idxHiB << endl;
PopHi(arrA, arrB, idxHiA, idxHiB);
cout << idxHiA << ", " << idxHiB << endl;
return 0;
}
Outputs
Original:
2, 0
1, 0 // ok
Version 1:
2, 0
2, -1 // also ok
Version 2:
2, 0
1, -1 // wtf??
you’re changing
idxHiAhere …… which bites you here. You want to use the old value of
idxHiA, but are using the decremented one (which could be illegal BTW). The element at that position is no longer the maximum.I suggest to store the result of the comparison to a boolean variable, that would be clearer to read.
PS: I would check in assembler that your “no-branch” version is actually without branches. Sometimes, operations with boolean variables are translated using branches.