我有2个2D点,它们被塞在一起成阵列:int square[4]
.这四个数字被解释为矩形的定义,其中水平线平行于X轴,垂直线平行于Y轴.然后,数组的元素分别定义:
左边的X坐标
底边的Y坐标
右边缘的X坐标
上边缘的Y坐标
我在这里定义了一个绕线顺序enum
:
enum WindingOrder { BOTTOM = 0, RIGHT, TOP, LEFT };
我的代码的最小,完整,可验证的例子是,我得到一个输出第二个数组:int output[4]
和一个输入WindingOrder edge
.我需要填写output
如下:
switch(edge) { case BOTTOM: output[0] = square[0]; output[1] = square[1]; output[2] = square[2]; output[3] = square[1]; break; case RIGHT: output[0] = square[2]; output[1] = square[1]; output[2] = square[2]; output[3] = square[3]; break; case TOP: output[0] = square[2]; output[1] = square[3]; output[2] = square[0]; output[3] = square[3]; break; case LEFT: output[0] = square[0]; output[1] = square[3]; output[2] = square[0]; output[3] = square[1]; break; }
我没有嫁给一个特定的WindingOrder
安排,也不关心分数的顺序ouptut
,所以如果改变那些使得这个可以解决,我就失望了.我想知道的是我可以构建square
索引以output
在for
循环中分配,而不使用if
/ case
/三元语句(换句话说使用逐位操作)?
所以我想要,给予int i = 0
并对WindingOrder edge
它们进行逐位操作以找到:
do { output[i] = array[???]; } while(++i <= LEFT);
编辑:
我收到了很多静态数组的答案(我相信这是解决这个问题的最佳方法,所以我给了+1).但作为一个逻辑问题,我很奇怪为什么很少有位操作可以动态地找到给定边的元素.因此,例如,如何把这个函数体被writen给出一个任意edge
和i
:int getIndex(int i, int edge)
这是一个不同的解决方案.它是静态数组方法的变体,但没有实际数组:索引矩阵内联为计算为常量表达式的32位无符号整数.通过edge
单个移位选择参数列,最后,通过简单的位移和屏蔽选择每个数组元素的各个索引.
该解决方案具有以下优点:
它很容易理解
它不使用测试
它不使用静态数组,也不使用任何其他内存位置
它独立于缠绕顺序,可以轻松定制任何阵列组件顺序
它不使用C99特定语法,这可能在C++中不可用.
这就像我可以得到一个按位解决方案一样接近.
#includeenum WindingOrder { BOTTOM = 0, RIGHT, TOP, LEFT }; void BitwiseWind(int const *input, int *output, enum WindingOrder edge) { unsigned bits = ((0x00010201 << BOTTOM * 2) | (0x02010203 << RIGHT * 2) | (0x02030003 << TOP * 2) | (0x00030001 << LEFT * 2)) >> (edge * 2); output[0] = input[(bits >> 24) & 3]; output[1] = input[(bits >> 16) & 3]; output[2] = input[(bits >> 8) & 3]; output[3] = input[(bits >> 0) & 3]; } int main() { enum WindingOrder edges[4] = { BOTTOM, RIGHT, TOP, LEFT }; int rect[4] = { 1, 3, 4, 5 }; int output[4]; for (int i = 0; i < 4; i++) { BitwiseWind(rect, output, edges[i]); std::cout << output[0] << output[1] << output[2] << output[3] << std::endl; } return 0; }
编译BitwiseWind
for x86-64
with clang -O3
生成21条指令,比静态数组版本多6条,但没有任何内存引用.这有点令人失望,但我希望它可以为ARM
目标生成更少的指令,利用位域提取操作码.顺便说一句,内联版本使用output[i] = array[(i+(i==winding)*2)&3];
产生25条指令而没有任何跳转,并且gcc -O3
更糟糕的是:它通过4次测试和跳转生成了更多的代码.
下面的通用getIndex
函数只编译为6 x86
条指令:
int getIndex(int i, int edge) { return (((0x00010201 << BOTTOM * 2) | (0x02010203 << RIGHT * 2) | (0x02030003 << TOP * 2) | (0x00030001 << LEFT * 2)) >> (edge * 2 + 24 - i * 8)) & 3; }