Hamming vekt - Hamming weight

Den Hamming-vekten av en streng er det antall symboler som er forskjellig fra null-symbol av alfabetet anvendes. Det tilsvarer dermed Hamming-avstanden fra nullstrengen av samme lengde. For det mest typiske tilfellet, en streng med biter , er dette tallet 1 i strengen, eller tallsummen for den binære representasjonen av et gitt tall og ₁ normen for en bitvektor. I dette binære tilfellet kalles det også befolkningstallet , popcount , summen sidelengs eller bit summering .

Eksempler
String Hamming vekt
111 0 1 4
111 0 1 000 4
00000000 0
678 0 1234 0 567 10
Et plott for befolkningstallet (Hammingvekt for binære tall) for (desimaltall) 0 til 256.

Historie og bruk

Hamming -vekten er oppkalt etter Richard Hamming, selv om han ikke stammer fra tanken. Hammingvekten til binære tall ble allerede brukt i 1899 av James WL Glaisher for å gi en formel for antall oddetall binomiske koeffisienter i en enkelt rad i Pascals trekant . Irving S. Reed introduserte et konsept, tilsvarende Hamming -vekt i binærhuset, i 1954.

Hammingvekt brukes i flere disipliner, inkludert informasjonsteori , kodeteori og kryptografi . Eksempler på anvendelser av Hamming -vekten inkluderer:

  • I modulær eksponentiering ved kvadrering er antallet modulære multiplikasjoner som kreves for en eksponent e log 2 e + vekt ( e ). Dette er grunnen til at den offentlige nøkkelverdien e som brukes i RSA vanligvis er valgt til å være et antall lav Hamming -vekt.
  • Hamming -vekten bestemmer banelengder mellom noder i akkordfordelte hashtabeller .
  • IrisCode -oppslag i biometriske databaser implementeres vanligvis ved å beregne Hamming -avstanden til hver lagrede post.
  • I datamaskinen sjakk programmer ved hjelp av en bitboard representasjon, Hamming vekten av en bitboard gir antallet av biter av en gitt type igjen i spillet, eller antallet av kvadrater av brettet styres av en spillers stykker, og er derfor en viktig medvirkende sikt til verdien av en posisjon.
  • Hammingvekt kan brukes til effektivt å beregne finn første sett ved hjelp av identiteten ffs (x) = pop (x ^ (x - 1)). Dette er nyttig på plattformer som SPARC som har Hamming -vektinstruksjoner for maskinvare, men ingen instruksjoner for første maskinvare finner.
  • Hamming -vektoperasjonen kan tolkes som en konvertering fra det unære tallsystemet til binære tall .
  • Ved implementering av noen kortfattede datastrukturer som bitvektorer og wavelet -trær .

Effektiv implementering

Befolkningstallet til en bitstreng er ofte nødvendig i kryptografi og andre applikasjoner. Den Hamming-avstand mellom to ord A og B kan beregnes som Hamming-vekten av A xor B .

Problemet med hvordan man implementerer det effektivt har blitt studert mye. En enkelt operasjon for beregningen eller parallelle operasjoner på bitvektorer er tilgjengelig på noen prosessorer . For prosessorer som mangler disse funksjonene, er de beste kjente løsningene basert på å legge til tellinger i et tremønster. For eksempel, for å telle antallet 1 bits i det 16-biters binære tallet a = 0110 1100 1011 1010, kan disse operasjonene utføres:

Uttrykk Binær Desimal Kommentar
a 01 10 11 00 10 11 10 10 27834 Det originale nummeret
b0 = (a >> 0) & 01 01 01 01 01 01 01 01 01 00 01 00 00 01 00 00 1, 0, 1, 0, 0, 1, 0, 0 Annen bit fra a
b1 = (a >> 1) & 01 01 01 01 01 01 01 01 00 01 01 00 01 01 01 01 0, 1, 1, 0, 1, 1, 1, 1 De resterende bitene fra a
c = b0 + b1 01 01 10 00 01 10 01 01 1, 1, 2, 0, 1, 2, 1, 1 Antall 1s i hver 2-bits bit av a
d0 = (c >> 0) & 0011 0011 0011 0011 0001 0000 0010 0001 1, 0, 2, 1 Annenhver telling fra ca.
d2 = (c >> 2) & 0011 0011 0011 0011 0001 0010 0001 0001 1, 2, 1, 1 De resterende tallene fra ca.
e = d0 + d2 0010 0010 0011 0010 2, 2, 3, 2 Antall 1s i hver 4-bits skive av a
f0 = (e >> 0) & 00001111 00001111 00000010 00000010 2, 2 Annenhver telling fra e
f4 = (e >> 4) & 00001111 00001111 00000010 00000011 2, 3 De gjenværende tellinger fra e
g = f0 + f4 00000100 00000101 4, 5 Antall 1s i hver 8-biters stykke a
h0 = (g >> 0) & 0000000011111111 0000000000000101 5 Annenhver telling fra g
h8 = (g >> 8) & 0000000011111111 0000000000000100 4 De resterende tallene fra g
i = h0 + h8 0000000000001001 9 Antall 1s i hele 16-biters ord

Her er operasjonene som i programmeringsspråk C , så X >> Ybetyr å skifte X til høyre med Y -biter, X og Y betyr bitvis AND for X og Y, og + er vanlig tillegg. De beste algoritmene som er kjent for dette problemet er basert på konseptet illustrert ovenfor og er gitt her:

//types and constants used in the functions below
//uint64_t is an unsigned 64-bit integer variable type (defined in C99 version of C language)
const uint64_t m1  = 0x5555555555555555; //binary: 0101...
const uint64_t m2  = 0x3333333333333333; //binary: 00110011..
const uint64_t m4  = 0x0f0f0f0f0f0f0f0f; //binary:  4 zeros,  4 ones ...
const uint64_t m8  = 0x00ff00ff00ff00ff; //binary:  8 zeros,  8 ones ...
const uint64_t m16 = 0x0000ffff0000ffff; //binary: 16 zeros, 16 ones ...
const uint64_t m32 = 0x00000000ffffffff; //binary: 32 zeros, 32 ones
const uint64_t h01 = 0x0101010101010101; //the sum of 256 to the power of 0,1,2,3...

//This is a naive implementation, shown for comparison,
//and to help in understanding the better functions.
//This algorithm uses 24 arithmetic operations (shift, add, and).
int popcount64a(uint64_t x)
{
    x = (x & m1 ) + ((x >>  1) & m1 ); //put count of each  2 bits into those  2 bits 
    x = (x & m2 ) + ((x >>  2) & m2 ); //put count of each  4 bits into those  4 bits 
    x = (x & m4 ) + ((x >>  4) & m4 ); //put count of each  8 bits into those  8 bits 
    x = (x & m8 ) + ((x >>  8) & m8 ); //put count of each 16 bits into those 16 bits 
    x = (x & m16) + ((x >> 16) & m16); //put count of each 32 bits into those 32 bits 
    x = (x & m32) + ((x >> 32) & m32); //put count of each 64 bits into those 64 bits 
    return x;
}

//This uses fewer arithmetic operations than any other known  
//implementation on machines with slow multiplication.
//This algorithm uses 17 arithmetic operations.
int popcount64b(uint64_t x)
{
    x -= (x >> 1) & m1;             //put count of each 2 bits into those 2 bits
    x = (x & m2) + ((x >> 2) & m2); //put count of each 4 bits into those 4 bits 
    x = (x + (x >> 4)) & m4;        //put count of each 8 bits into those 8 bits 
    x += x >>  8;  //put count of each 16 bits into their lowest 8 bits
    x += x >> 16;  //put count of each 32 bits into their lowest 8 bits
    x += x >> 32;  //put count of each 64 bits into their lowest 8 bits
    return x & 0x7f;
}

//This uses fewer arithmetic operations than any other known  
//implementation on machines with fast multiplication.
//This algorithm uses 12 arithmetic operations, one of which is a multiply.
int popcount64c(uint64_t x)
{
    x -= (x >> 1) & m1;             //put count of each 2 bits into those 2 bits
    x = (x & m2) + ((x >> 2) & m2); //put count of each 4 bits into those 4 bits 
    x = (x + (x >> 4)) & m4;        //put count of each 8 bits into those 8 bits 
    return (x * h01) >> 56;  //returns left 8 bits of x + (x<<8) + (x<<16) + (x<<24) + ... 
}

Ovennevnte implementeringer har den beste verste oppførselen til noen kjent algoritme. Imidlertid, når en verdi forventes å ha få bits uten null, kan det i stedet være mer effektivt å bruke algoritmer som teller disse bitene en om gangen. Som Wegner beskrev i 1960, er bitvis OG av x med x  - 1 forskjellig fra x bare ved å nullstille den minst signifikante nullbiten: subtrahering 1 endrer den høyeste strengen på 0s til 1s, og endrer den høyre til en 0. Hvis x opprinnelig hadde n biter som var 1, så etter bare n iterasjoner av denne operasjonen, vil x bli redusert til null. Følgende implementering er basert på dette prinsippet.

//This is better when most bits in x are 0
//This algorithm works the same for all data sizes.
//This algorithm uses 3 arithmetic operations and 1 comparison/branch per "1" bit in x.
int popcount64d(uint64_t x)
{
    int count;
    for (count=0; x; count++)
        x &= x - 1;
    return count;
}

Hvis større minnebruk er tillatt, kan vi beregne Hamming -vekten raskere enn metodene ovenfor. Med ubegrenset minne kan vi ganske enkelt lage et stort oppslagstabell med Hamming -vekten for hvert 64 -bits heltall. Hvis vi kan lagre en oppslagstabell for hammingfunksjonen til hvert 16 -bits heltall, kan vi gjøre følgende for å beregne Hamming -vekten for hvert 32 -bits heltall.

static uint8_t wordbits[65536] = { /* bitcounts of integers 0 through 65535, inclusive */ };
//This algorithm uses 3 arithmetic operations and 2 memory reads.
int popcount32e(uint32_t x)
{
    return wordbits[x & 0xFFFF] + wordbits[x >> 16];
}
//Optionally, the wordbits[] table could be filled using this function
int popcount32e_init(void)
{
    uint32_t i;
    uint16_t x;
    int count;
    for (i=0; i <= 0xFFFF; i++)
    {
        x = i;
        for (count=0; x; count++) // borrowed from popcount64d() above
            x &= x - 1;
        wordbits[i] = count;
    }
}

Muła et al. har vist at en vektorisert versjon av popcount64b kan kjøre raskere enn dedikerte instruksjoner (f.eks. popcnt på x64 -prosessorer).

Minste vekt

Ved feilkorrigerende koding er minimum Hamming-vekt, vanligvis referert til som minimumsvekten w min av en kode, vekten av det laveste vekt-ikke-null kodeordet. Vekten w av et kodeord er tallet 1s i ordet. For eksempel har ordet 11001010 en vekt på 4.

I en lineær blokkode er minimumsvekten også minimum Hamming -avstand ( d min ) og definerer feilkorrigeringsevnen til koden. Hvis w min  =  n , så d min  =  n og koden vil korrigere opptil d min /2 feil.

Språkstøtte

Noen C -kompilatorer har innebygde funksjoner som gir mulighet for bittelling. For eksempel inkluderer GCC (siden versjon 3.4 i april 2004) en innebygd funksjon __builtin_popcountsom vil bruke en prosessorinstruksjon hvis tilgjengelig eller en effektiv bibliotekimplementering på annen måte. LLVM-GCC har inkludert denne funksjonen siden versjon 1.5 i juni 2005.

I C ++ STL har bit-array datastrukturen bitseten count()metode som teller antall biter som er satt. I C ++ 20 ble en ny overskrift <bit>lagt til, som inneholder funksjoner std::popcountog std::has_single_bittar argumenter av usignerte heltallstyper.

I Java har den voksbare bit-array datastrukturen BitSeten BitSet.cardinality()metode som teller antall biter som er satt. I tillegg er det Integer.bitCount(int)og Long.bitCount(long)funksjoner for å telle biter i henholdsvis primitive 32-bits og 64-bits heltall. Heltallklassen BigIntegervilkårlig presisjon har også en BigInteger.bitCount()metode som teller biter.

I Python har inttypen en bit_count()metode for å telle antall biter som er angitt. Denne funksjonaliteten er ny i Python 3.10, planlagt for utgivelse i 2021.

I Common Lisplogcount returnerer funksjonen , gitt et ikke-negativt heltall, antallet 1 biter. (For negative heltall returnerer det antallet 0 bits i 2s komplementnotasjon.) I begge tilfeller kan heltallet være et BIGNUM.

Fra og med GHC 7.4 har Haskell -basepakken en popCountfunksjon tilgjengelig på alle typer som er forekomster av Bitsklassen (tilgjengelig fra Data.Bitsmodulen).

MySQL -versjon av SQL -språk gir BIT_COUNT()som en standardfunksjon.

Fortran 2008 har standard, iboende, elementær funksjon som popcntreturnerer antall ikke -null biter i et heltall (eller heltall array).

Noen programmerbare vitenskapelige lommekalkulatorer har spesielle kommandoer for å beregne antall settbiter , f.eks. #BHP-16C og WP 43S , #BITSeller BITSUMpå HP-16C-emulatorer, og nBITSWP 34S .

Free Pascal redskaper popcnt siden versjon 3.0.

Prosessorstøtte

Se også

Referanser

Videre lesning

Eksterne linker