GCC内建函数C语言实现__builtin_popcountll,__builtin_ctzll,__buitlin_clzll

C语言编程有时需要用到__builtin_popcountll,__builtin_ctzll,__buitlin_clzll等GCC内建函数,这里给出了简单的实现代码,算法实现肯定不是最优的但可以使用,大端模式CPU没有验证!!

/**
哈希表
记录0~255每个数的二进制表示1的个数
如:1,0b0001  有1个1
    2,0b0010  有1个1
    3,0b0011  有2个1
*/
int poptable[256] = {
    0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4,
    1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
    1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
    2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
    1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
    2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
    2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
    3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
    1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
    2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
    2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
    3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
    2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
    3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
    3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
    4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8
};

// big - endian和little - endian
enum {
    E_CPU_BIG_ENDIAN = 0, // 大端模式
    E_CPU_LITTLE_ENDIAN = 1   // 小端模式
};

/*
判断CPU大小端模式
小端模式中:低位字节放在低地址,高位字节放在高地址;little-endian
大端模式中,低位字节放在高地址,高位字节放在低地址;big-endian
*/
char cpu_endian(void)
{
    union {
        int a;
        char b;
    }c;

    c.a = 1;
    if (c.b == 1) {
        /* CPU 是 小端模式 */
        return E_CPU_LITTLE_ENDIAN;
    }
    else {

        /* CPU 是 大端模式 */
        return E_CPU_BIG_ENDIAN;
    }

    return 0;
}

/* 
计算x以二进制表示法包含1的个数
*/
int __builtin_popcountll(unsigned long long x) 
{
    int count = 0;
    int i = 0;
    for (i = 0; i < 8; i++) {
        count += poptable[(x >> (8 * i)) & 0xff];
    }
    return count;
}

/**
计算 x 二进制表示形式中末尾0的个数。
*/
int __builtin_ctzll(unsigned long long x)
{
    
    // 0x1122334455667788
    // 2,6,10,14  后面有1个零
    // 4,12 后面有2个零
    // 8 后面有3个零
    /*
        0000    0       0
        0001    1       1
        0010    2       2
        0011    3       3
        0100    4       4
        0101    5       5
        0110    6       6
        0111    7       7
        1000    8       8
        1001    9       9
        1010    10      A
        1011    11      B
        1100    12      C
        1101    13      D
        1110    14      E
        1111    15      F
    */

    int count = 0;
    if (cpu_endian() == E_CPU_BIG_ENDIAN)
    {
        // 大端模式  数据转成小端模式,即数据高低字节对调
        // 0x1122334455667788
        // 0x8877665544332211
        x = (((x >> 56) & 0xFF) | (((x >> 48) & 0xFF) << 8) | (((x >> 40) & 0xFF) << 16) | (((x >> 32) & 0xFF) << 24) | (((x >> 24) & 0xFF) << 32) | (((x >> 16) & 0xFF) << 40) | (((x >> 8) & 0xFF) << 48) | ((x & 0xFF) << 56));    
    }
    else 
    {
        // 小端模式
    }
    int i = 0;
    for (i = 0; i < 8; i++) {
        unsigned char j = (x>>(i*8) & 0xFF);
        if (0 == j) {
            count += 8;
        }
        else 
        {
            unsigned char n=0;
            unsigned char L = (j & 0x0F);
            unsigned char H = ((j>>4) & 0x0F);
            n = L;
            if (0 == L) {
                count += 4;
                n = H;
            }
            // 2,6,10,14  后面有1个零
            if ((2 == n) || (6 == n) || (10 == n) || (14 == n)) {
                count += 1;
            }
            // 4,12 后面有2个零
            else if ((4==n)||(12==n)) 
            {
                count += 2;
            }
            // 8 后面有3个零
            else if (8==n) 
            {
                count += 3;
            }
            break;
        }       
    }
    return count;
}

/* 返回括号内数的二进制表示形式中前导0的个数。 */
int __buitlin_clzll(unsigned long long x)
{
    // 0x1122334455667788
    // 4,5,6,7  前面有1个零
    // 2,3      前面有2个零
    // 1        前面有3个零
   
    /*
        0000    0       0
        0001    1       1
        0010    2       2
        0011    3       3
        0100    4       4
        0101    5       5
        0110    6       6
        0111    7       7
        1000    8       8
        1001    9       9
        1010    10      A
        1011    11      B
        1100    12      C
        1101    13      D
        1110    14      E
        1111    15      F
    */
    // 0x000000000120
    int count = 0;
    if (cpu_endian() == E_CPU_BIG_ENDIAN)
    {
        // 大端模式  数据转成小端模式,即数据高低字节对调
        // 0x1122334455667788
        // 0x8877665544332211
        x = (((x >> 56) & 0xFF) | (((x >> 48) & 0xFF) << 8) | (((x >> 40) & 0xFF) << 16) | (((x >> 32) & 0xFF) << 24) | (((x >> 24) & 0xFF) << 32) | (((x >> 16) & 0xFF) << 40) | (((x >> 8) & 0xFF) << 48) | ((x & 0xFF) << 56));
    }
    else
    {
        // 小端模式
    }
    
    int i = 0;
    for (i = 7; i >= 0; i--) {
        unsigned char j = ((x >> (i * 8)) & 0xFF);
        if (0 == j) {
            count += 8;
        }
        else 
        {
            unsigned char n = 0;
            unsigned char L = (j & 0xF);
            unsigned char H = (j >> 4) & 0xF;
            
            if (0 == H) {
                count += 4;
                n = L;
            }
            // 4,5,6,7  前面有1个零
            // 2,3      前面有2个零
            // 1        前面有3个零
            if (1 == n) {
                count += 3;
            }
            else if ((2 == n) || (3 == n)) {
                count += 2;
            }
            else if ((4 == n) || (5 == n) || (6 == n) || (7 == n)) {
                count += 1;
            }
            break;
        }
    }
    return count;
}

你可能感兴趣的:(C语言,c语言,算法,开发语言)