«   2024/04   »
1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30
Archives
Today
Total
관리 메뉴

Code Run

Bitwise pop count and find first set 본문

코딩 tip

Bitwise pop count and find first set

comkiwer 2016. 12. 15. 15:41


A Swar Algorithm for popcount 



1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
/**
Bitwise pop count and find first set
Find First Set
get least significant bit index
comkiwer
https://www.playingwithpointers.com/blog/swar.html
*/
#include <cstdio>
 
typedef unsigned int UI;
 
UI popcount(UI x){
    x -= (x>>1& 0x55555555;
    x = (x&0x33333333+ ((x>>2)&0x33333333);
    return (((x+(x>>4))&0x0F0F0F0F)*0x01010101)>>24;
}
 
/***
swar 코드를 풀어 보면 아래와 같다.
swar 코드는
2비트에서 나올 수 있는 popcount는 2비트(3)를 넘지 않고,
8비트에서 나올 수 있는 popcount는 4비트(15)를 넘지 않고,
32비트에서 나올 수 있는 popcount는 8비트(127)를 넘지 않는 특징을 이용한다.
< 2개의 비트씩 구하기 >
j = (i >> 1) & 0x55555555; 짝수 비트 자리의 1인 비트 남기기
i = i - j; // 결국엔 두개의 비트씩 popcount를 구하는 것이다.
두 비트는 아래 4가지가 있다.
00 에서 popcount는 0개 (00 - 00 = 00)
01 에서 popcount는 1개 (01 - 00 = 01)
10 에서 popcount는 1개 (10 - 01 = 01)
11 에서 popcount는 2개 (11 - 01 = 10)
< 4개의 비트씩 구하기 >
i = (i & 0x33333333) + ((i >> 2) & 0x33333333);
< 8개의 비트씩 구하기 >
i = (i & 0x0F0F0F0F) + ((i >> 4) & 0x0F0F0F0F)
그런데 8비트에서 popcount는 4비트를 넘지 않으므로
i = ((i + (i>>4)) & 0x0F0F0F0F) 로 줄여 쓸 수 있다.
< 전체 비트수 구하기 >
8개의 비트씩 나누어 구한 결과가 8비트씩 4곳에 저장되어 있다.
i = i * 0x01010101
i = i>>24           를 이해 하기 위하여 아래 예를 보자.
abcd * 1111의 결과는 아래와 같다.
   (a)bcd
  a(b)cd
 ab(c)d
abc(d)
비트 연산에서는 ()값들 왼쪽 값은 범위를 벗어나므로 버림된다.
남은 값에서 ()값들만 남기는 것이 i = i>>24이다.
*/
 
 
 
UI popcount2(UI x){
    x = (x & 0x55555555+ ((x>>1& 0x55555555);
    x = (x & 0x33333333+ ((x>>2& 0x33333333);
    x = (x & 0x0F0F0F0F+ ((x>>4& 0x0F0F0F0F);
    x = (x & 0x00FF00FF+ ((x>>8& 0x00FF00FF);
    x = (x & 0x0000FFFF+ ((x>>16& 0x0000FFFF);
    return x;
 
}
 
UI ffs(UI x){
    if(!x) return 0;
    return popcount((x&-x)-1)+1;
}
 
 
UI popcount64(UI x) {
  x -= ((x >> 1& 0x5555555555555555);
  x = (x & 0x3333333333333333+ ((x >> 2& 0x3333333333333333);
  return (((x + (x >> 4)) & 0x0F0F0F0F0F0F0F0F* 0x0101010101010101>> 56;
 
}
 
int main(){
    int i, N = 10000000;
    for(i=1;i<=N;++i){
        int p1 = __builtin_ffs(i);
        int p2 = ffs(i);
        if(p1 != p2){
            printf("%d : %d %d\n", i, p1, p2);
        }
    }
    return 0;
}
cs