Question

Je veux extraire les n bits les plus importants d'un entier en C ++ et convertir ces n bits en un entier.

Par exemple

int a=1200;
// its binary representation within 32 bit word-size is
// 00000000000000000000010010110000

Maintenant, je veux extraire les 4 chiffres les plus significatifs de cette représentation, c'est-à-dire 1111

00000000000000000000010010110000
                     ^^^^

et convertir à nouveau en un entier (1001 en décimal= 9).

Comment est possible avec une fonction simple C ++ sans boucles?

Était-ce utile?

La solution

Certains processeurs ont une instruction pour compter les principaux zéros binaires d'un entier, et certains compilateurs ont des instruments d'instruments pour vous permettre d'utiliser cette instruction.Par exemple, en utilisant GCC:

uint32_t significant_bits(uint32_t value, unsigned bits) {
    unsigned leading_zeros = __builtin_clz(value);
    unsigned highest_bit = 32 - leading_zeros;
    unsigned lowest_bit = highest_bit - bits;

    return value >> lowest_bit;
}

Pour la simplicité, j'ai laissé des chèques sur lesquels le nombre de bits demandé est disponible.Pour le compilateur de Microsoft, le intrinsèque est appelé __lzcnt.

Si votre compilateur ne fournit pas ce processeur intrinsèque et que votre processeur n'a pas d'instruction appropriée, un moyen de compter rapidement les zéros est avec une recherche binaire:

unsigned leading_zeros(int32_t value) {
    unsigned count = 0;
    if ((value & 0xffff0000u) == 0) {
        count += 16;
        value <<= 16;
    }
    if ((value & 0xff000000u) == 0) {
        count += 8;
        value <<= 8;
    }
    if ((value & 0xf0000000u) == 0) {
        count += 4;
        value <<= 4;
    }
    if ((value & 0xc0000000u) == 0) {
        count += 2;
        value <<= 2;
    }
    if ((value & 0x80000000u) == 0) {
        count += 1;
    }
    return count;
}

Autres conseils

Ce n'est pas rapide, mais (int)(log(x)/log(2) + .5) + 1 vous dira la position du bit non nul le plus important.Finir l'algorithme de là est assez simple.

Cela semble fonctionner (fait en C # avec UINT32 puis porté des excuses de Bjarne):

        unsigned int input = 1200;
        unsigned int most_significant_bits_to_get = 4;
        // shift + or the msb over all the lower bits
        unsigned int m1 = input | input >> 8 | input >> 16 | input >> 24;
        unsigned int m2 = m1 | m1 >> 2 | m1 >> 4 | m1 >> 6;
        unsigned int m3 = m2 | m2 >> 1;
        unsigned int nbitsmask = m3 ^ m3 >> most_significant_bits_to_get;

        unsigned int v = nbitsmask;
        unsigned int c = 32; // c will be the number of zero bits on the right
        v &= -((int)v);
        if (v>0) c--;
        if ((v & 0x0000FFFF) >0) c -= 16;
        if ((v & 0x00FF00FF) >0) c -= 8;
        if ((v & 0x0F0F0F0F) >0 ) c -= 4;
        if ((v & 0x33333333) >0) c -= 2;
        if ((v & 0x55555555) >0) c -= 1;

        unsigned int result = (input & nbitsmask) >> c;

J'ai supposé que vous vouliez dire en utilisant uniquement des mathématiques entier.

J'ai utilisé du code de @ @ Olicarlesworth's Link, vous pouvez supprimer également les conditionnels en utilisant la lutt pour le code zéros traînant là-bas.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top