summaryrefslogtreecommitdiffstats
path: root/ps1/lsb.c
blob: c0fac2ca9839115360cbc7b7928e7e7d717f0662 (plain)
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
#include <stdio.h>

const unsigned int w = 16;
const unsigned int l = 4; // sqrt(w)
const unsigned int b = 0x8888; // 1000 1000 1000 1000
const unsigned int a = 0x1111; // 0001 0001 0001 0001
const unsigned int mm = 0xf;   // 0000 0000 0000 1111
const unsigned int m = 0x2490; // 0010 0100 1001 0000
const unsigned int c = 0xf731; // 1111 0111 0011 0001

char* itoa(unsigned int i, char* str, unsigned int base) {
    const char chars[] = "0123456789abcdef";
    char* p = str; char b;
    while (i) {
        *str++ = chars[i % base];
        i /= base;
    }
    *str = '\0';
    while (p < str) { // reverse str through pairwise swapping
        b = *p;
        *p++ = *--str;
        *str = b; 
    }
    return str;
}

void print_n(unsigned int i) {
    char buffer[2*w];
    itoa(i, buffer, 2);
    printf("%s\n", buffer);
}

/* assumes that x is 0 everywhere except possibly the leading bit of each block
 * and computes the number of leading bits equal to one (4 op) */
unsigned int count_ones(unsigned int x) { return ((x * a) >> (w-1)) & mm; }

/* assumes that x is 0 everywhere except possibly the leading bit of each block
 * and compress the leading bits of each block into the least significant
 * block keeping their order (3 op) */
unsigned int perfect_sketch(unsigned int x) { return ((x * m) >> w) & mm; }

/* assumes that x consists of a single block and repeat it l times (1 op) */
unsigned int repeat(unsigned int x) { return x * a; }

/* the leading bit of each block indicates whether or not the corresponding
 * block in x is empty or not (7 op) */
unsigned int non_empty_clusters(unsigned int x) { return (x & b) | (b & ~( b - (x & ~b))); }

/* the leading bit of each block indicates whether or not the corresponding
 * block in x is empty or not (6 op) */
unsigned int empty_clusters(unsigned int x) { return (x ^ b) & (b & ( b - (x & ~b))); }

/* computes the lsb of a single block (10 op) */
unsigned int lsb_short(unsigned int x) {
    return count_ones(empty_clusters(repeat(x) & c));
}

/* computes the lsb of x (34 op) */
unsigned int lsb(unsigned int x) {
    int z = lsb_short(perfect_sketch(non_empty_clusters(x)));
    if (z == l) {
        return -1;
    } else {
        return z*l + lsb_short((x >> z * l) & mm);
    }
}

int main() {
    unsigned int i = 0x8a00;
    print_n(i);
    printf("%d\n", lsb(i));
}