我不确定我是否正确推断了这些值,但如果我这样做了,
unsigned field_ref_dist(unsigned cur, unsigned ref) {
return ((cur - ref - 1) & ~1u) + ((cur - ref) & !!ref);
}
可以:
f(1, 0) = 0
f(2, 1) = 1
f(2, 0) = 0
f(3, 2) = 1
f(3, 1) = 0
f(3, 0) = 2
f(4, 3) = 1
f(4, 2) = 0
f(4, 1) = 3
f(4, 0) = 2
f(5, 4) = 1
f(5, 3) = 0
f(5, 2) = 3
f(5, 1) = 2
f(5, 0) = 4
f(6, 5) = 1
f(6, 4) = 0
f(6, 3) = 3
f(6, 2) = 2
f(6, 1) = 5
f(6, 0) = 4
f(7, 6) = 1
f(7, 5) = 0
f(7, 4) = 3
f(7, 3) = 2
f(7, 2) = 5
f(7, 1) = 4
f(7, 0) = 6
f(8, 7) = 1
f(8, 6) = 0
f(8, 5) = 3
f(8, 4) = 2
f(8, 3) = 5
f(8, 2) = 4
f(8, 1) = 7
f(8, 0) = 6
f(9, 8) = 1
f(9, 7) = 0
f(9, 6) = 3
f(9, 5) = 2
f(9, 4) = 5
f(9, 3) = 4
f(9, 2) = 7
f(9, 1) = 6
f(9, 0) = 8
它甚至可能和查找表一样快。
暂时不考虑大小写ref == 0
和cur
奇数,这些值自然可以成对分组(2*k, 2*k+1)
,并且值仅取决于cur - ref
那里的差异。
交换这些对,我们只需cur - ref - 1
. 所以为了得到这些对的较小值2*k
——我们可以屏蔽掉最低有效位,因此
(cur - ref - 1) & ~1u
现在,对的顺序实际上是较大的(奇数)值来自较小的(奇数)差异,所以1
如果差异是奇数,我们添加,
((cur - ref - 1) & ~1u) + ((cur - ref) & 1u)
这适用于除cur
奇数和之外的所有情况ref == 0
,在这种情况下,值必须是cur - 1
(然后是偶数,因此& ~1u
不会改变它)而不是((cur - ref - 1) & ~1u) + ((cur - ref) & 1u)
。
所以对于这种特殊情况,加数应该是0
而不是1
。我们从 中得到它(cur - ref) & 0
,因此我们需要一个产生1
非零ref
和[如果0
是偶数,则差也是偶数,并且,因此用for ] 替换不会触及的操作。这是通过 实现的。ref == 0
cur
((cur - ref) & 1u) == 0
1u
0
ref == 0
!!ref