하나의 접근법 - 니블로 분할 한 다음 스위치를 사용하여 니블에서 비트를 선택하십시오. 선택한 비트가 컴파일 타임에 알려지고 코드를 풀 수 있도록 템플릿을 사용하십시오.
template < int i, int x >
struct process_bit {
inline static void apply (int y) { };
};
template < int x >
struct process_bit < 1, x > {
inline static void apply (int y) {
evaluate (x, y);
}
};
template < int x, int n >
inline void process_nibble_bits (int y) {
process_bit < x & 1, n >::apply(y);
process_bit < (x >> 1) & 1, n + 1 > ::apply(y);
process_bit < (x >> 2) & 1, n + 2 > ::apply(y);
process_bit < (x >> 3) & 1, n + 3 > ::apply(y);
}
template < int n >
inline void process_nibble (uint64_t xbits, int y) {
uint64_t nibble = (xbits >> n) & 0xf;
if (nibble) {
switch (nibble) {
case 0:
process_nibble_bits < 0, n > (y);
break;
case 1:
process_nibble_bits < 1, n > (y);
break;
case 2:
process_nibble_bits < 2, n > (y);
break;
case 3:
process_nibble_bits < 3, n > (y);
break;
case 4:
process_nibble_bits < 4, n > (y);
break;
case 5:
process_nibble_bits < 5, n > (y);
break;
case 6:
process_nibble_bits < 6, n > (y);
break;
case 7:
process_nibble_bits < 7, n > (y);
break;
case 8:
process_nibble_bits < 8, n > (y);
break;
case 9:
process_nibble_bits < 9, n > (y);
break;
case 10:
process_nibble_bits < 10, n > (y);
break;
case 11:
process_nibble_bits < 11, n > (y);
break;
case 12:
process_nibble_bits < 12, n > (y);
break;
case 13:
process_nibble_bits < 13, n > (y);
break;
case 14:
process_nibble_bits < 14, n > (y);
break;
case 15:
process_nibble_bits < 15, n > (y);
break;
}
}
}
template < int i, int n >
struct bit_tree {
inline static void apply (uint64_t xbits, int y) {
// each call to here represents scan of bits in [ n, n + 2i)
bit_tree <i>> 1, n > ::apply(xbits, y);
bit_tree <i>> 1, n + i > ::apply(xbits, y);
};
};
template < int i, int n >
struct bit_tree_with_guard {
inline static void apply (uint64_t xbits, int y) {
// each call to here represents scan of bits in [ n, n + 2i)
// so this branch to execute if any in [ n, n + i) are set
if (xbits & (((((uint64_t) 1LL) << i) - 1) << n))
bit_tree <i>> 1, n > ::apply(xbits, y);
if (xbits & (((((uint64_t) 1LL) << i) - 1) << (n + i)))
bit_tree <i>> 1, n + i > ::apply(xbits, y);
};
};
// put guards on 8 and 16 bit blocks (for some reason using inheritance is slower)
template < int n >
struct bit_tree < 8, n > {
inline static void apply (uint64_t xbits, int y) {
bit_tree_with_guard < 8, n > ::apply (xbits, y);
}
};
template < int n >
struct bit_tree < 16, n > {
inline static void apply (uint64_t xbits, int y) {
bit_tree_with_guard < 16, n > ::apply (xbits, y);
}
};
template < int n >
struct bit_tree < 2, n > {
inline static void apply (uint64_t xbits, int y) {
process_nibble <n> (xbits, y);
}
};
void template_nibbles(int height) {
for (int y = 0; y < height; y++) {
uint64_t xbits = ~board[y];
bit_tree< 32, 0>::apply (xbits, y);
}
}
는 최대한 빨리 FFS 버전과 아니에요 실행,하지만 다른 휴대용 것보다 터치 더 나은, 그리고 결과에 그들과 함께 일관되게 나타납니다
$ bin\bit_twiddle_micro_opt.exe
testing will_while()... 3375000 usecs (check 1539404233,1539597930)
testing will_ffs()... 2890625 usecs (check 675191567,1001386403)
testing alphaneo_unrolled_8()... 3296875 usecs (check 1539404233,1539597930)
testing template_nibbles()... 3046875 usecs (check 1539404233,1539597930)
모든 나무를 사용하여 길은 어떤 이득도주지 않는 것처럼 보입니다. 니블 스위치를 사용하지 않으면 속도가 느려집니다. 누구든지 C++만을 사용하여 손으로 16 가지 경우를 작성하지 않아도되는 방법을 알고 있습니까?
"찾는 - 다음 - 설정되지 않은 비트 논리"가 많은 시간을 소비한다는 것이 이상합니다. 실제로 처리되는 비트가 거의없는 경우 "while (bits)"문으로 문제를 해결해야합니다. 또한 uint32 절반을 모두 0 또는 4 단위로 확인하고 필요한 부분 만 처리 할 수 있습니다. BTW, 때때로 "xbits <0"은 "xbits & 1"보다 빠를 수 있습니다. 따라서 yuo는 int64_t xbits와 xbits << = 1을 사용할 수 있습니다. (x - 63에서 0까지) – zxcat