El peso de Hamming de una cadena de caracteres es el número de símbolos que son diferentes del símbolo cero del alfabeto utilizado. Por lo tanto, es equivalente a la distancia de Hamming de la cadena de ceros de la misma longitud. Para el caso más típico, una cadena de bits, este es el número de unos en la cadena, o la suma de dígitos de la representación binaria de un número dado y la norma ℓ₁ de un vector de bits. En el caso binario, también se denomina recuento de población,[4] suma lateral,[5] o suma de bits.[6]
La exponenciación binaria modular; el número de multiplicaciones modulares necesarias para un exponente e es log2e + peso(e). Esta es la razón por la que el valor de la clave pública e que se utiliza en RSA normalmente se elige como un número de bajo peso de Hamming.[10]
En los programas de ajedrez por computadora que utilizan una representación bitboard, el peso de Hamming de un tablero de bits da el número de piezas de un tipo determinado que quedan en el juego, o el número de casillas del tablero controlado por las piezas de un jugador y, por lo tanto, es un término contribuyente importante al valor de una posición.
El peso de Hamming se puede usar para encontrar el primer conjunto de manera eficiente usando la identidad ffs(x) = pop(x ^ (x - 1)). Esto es útil en plataformas como Sun SPARC que tienen instrucciones de peso de Hamming de hardware pero ninguna instrucción de primer conjunto de búsqueda de hardware.[12][4]
El conteo de población de un flujo de datos a menudo se necesita en criptografía y otras aplicaciones. La distancia de Hamming de dos palabras A y B se puede calcular como el peso de Hamming de exclusivamenteA o B.[4]
El problema de cómo determinarlo de manera eficiente ha sido ampliamente estudiado. Una sola operación para el cálculo, u operaciones paralelas sobre vectores de bits son disponible en algunos procesadores. Para los procesadores que carecen de esas funciones, las mejores soluciones conocidas se basan en agregar cuentas en un patrón de árbol. Por ejemplo, para contar el número de 1 bits en el número binario de 16 bits a = 0110 1100 1011 1010, se pueden realizar estas operaciones:
Expresión
Binaria
Decimal
Comentario
a
01
10
11
00
10
11
10
10
El número original
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
Cada otro bit de 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
Los bits restantes de a
c= b0 + b1
01
01
10
00
01
10
01
01
1, 1, 2, 0, 1, 2, 1, 1
Recuento de unos en cada porción de 2 bits de a
d0= (c >> 0) & 0011 0011 0011 0011
0001
0000
0010
0001
1, 0, 2, 1
Todos los demás contados desde c
d2= (c >> 2) & 0011 0011 0011 0011
0001
0010
0001
0001
1, 2, 1, 1
Los restantes contados desde c
e= d0 + d2
0010
0010
0011
0010
2, 2, 3, 2
Recuento de unos en cada porción de 4 bits de a
f0= (e >> 0) & 00001111 00001111
00000010
00000010
2, 2
Todos los demás contados desde e
f4= (e >> 4) & 00001111 00001111
00000010
00000011
2, 3
El resto contados desde e
g= f0 + f4
00000100
00000101
4, 5
Recuento de unos en cada segmento de 8 bits de a
h0= (g >> 0) & 0000000011111111
0000000000000101
5
Todos los demás contados desde g
h8= (g >> 8) & 0000000011111111
0000000000000100
4
El resto contados desde g
i= h0 + h8
0000000000001001
9
Recuento de unos en una palabra completa de 16 bits
Aquí, las operaciones son como en lenguaje de programación C, por lo que X >> Y significa desplazar X a la derecha en Y bits, X & Y significa el AND bit a bit de X e Y, y + es una suma ordinaria. Los mejores algoritmos conocidos para este problema se basan en el concepto ilustrado anteriormente y se proporcionan aquí:[4]
//Tipos de variables y constantes usados en las siguientes funciones//uint64_t es un tipo de variable entera de 64 bits sin signo (definida en la versión C99 del lenguaje C)constuint64_tm1=0x5555555555555555;//binary: 0101...constuint64_tm2=0x3333333333333333;//binary: 00110011..constuint64_tm4=0x0f0f0f0f0f0f0f0f;//binary: 4 zeros, 4 ones ...constuint64_tm8=0x00ff00ff00ff00ff;//binary: 8 zeros, 8 ones ...constuint64_tm16=0x0000ffff0000ffff;//binary: 16 zeros, 16 ones ...constuint64_tm32=0x00000000ffffffff;//binary: 32 zeros, 32 onesconstuint64_th01=0x0101010101010101;//the sum of 256 to the power of 0,1,2,3...//Esto es un ejemplo simple, que se muestra a modo de comparación,//y para ayudar a comprender mejor las funciones.//El algoritmo utiliza 24 operaciones aritméticas (shift, add, and).intpopcount64a(uint64_tx){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 returnx;}//Este ejemplo usa menos operaciones aritméticas que cualquier otra aplicación//conocida en máquinas con multiplicación lenta.//El algoritmo utiliza 17 operaciones aritméticas.intpopcount64b(uint64_tx){x-=(x>>1)&m1;//put count of each 2 bits into those 2 bitsx=(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 bitsx+=x>>16;//put count of each 32 bits into their lowest 8 bitsx+=x>>32;//put count of each 64 bits into their lowest 8 bitsreturnx&0x7f;}//Este ejemplo usa menos operaciones aritméticas que cualquier otra aplicación//conocida en máquinas con multiplicación rápida.//El algoritmo utiliza 12 operaciones aritméticas, una de las cuales es una multiplicación.intpopcount64c(uint64_tx){x-=(x>>1)&m1;//put count of each 2 bits into those 2 bitsx=(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) + ... }
Las aplicaciones anteriores tienen el mejor comportamiento en el peor de los casos de cualquier algoritmo conocido. Sin embargo, cuando se espera que un valor tenga pocos bits distintos de cero, puede ser más eficiente utilizar algoritmos que cuenten estos bits de uno en uno. Como Wegner describió en 1960,[14] el operador a nivel de bits de x con x - 1 difiere de x solo en poner a cero el bit distinto de cero menos significativo: restar 1 cambia el bit más a la derecha de la cadena de 0s a 1s, y cambia el 1 más a la derecha a un 0. Si x originalmente tenía n bits que eran 1, entonces después de solo n iteraciones de esta operación, x se reducirá a cero. El siguiente ejemplo se basa en este principio.
//Esta aplicación es mejor cuando la mayoría de los bits en x son 0//El algoritmo funciona igual para todos los tamaños de datos.//Usa 3 operaciones aritméticas y 1 comparación/rama por "1" bit en x.intpopcount64d(uint64_tx){intcount;for(count=0;x;count++)x&=x-1;returncount;}
Si se permite un mayor uso de memoria, se puede calcular el peso de Hamming más rápidamente que con los métodos anteriores. Con memoria ilimitada, se podría simplemente crear una gran tabla de búsqueda del peso de Hamming de cada entero de 64 bits. Si se puede almacenar una tabla de búsqueda de la función de Hamming de cada entero de 16 bits, se puede hacer lo siguiente para calcular el peso de Hamming de cada entero de 32 bits.
staticuint8_twordbits[65536]={/* bitcounts of integers 0 through 65535, inclusive */};//Este algoritmo utiliza 3 operaciones aritméticas y 2 lecturas de memoria.intpopcount32e(uint32_tx){returnwordbits[x&0xFFFF]+wordbits[x>>16];}
//Opcionalmente, la tabla wordbits[] podría rellenarse usando esta funciónintpopcount32e_init(void){uint32_ti;uint16_tx;intcount;for(i=0;i<=0xFFFF;i++){x=i;for(count=0;x;count++)// borrowed from popcount64d() abovex&=x-1;wordbits[i]=count;}}
Muła et al.[15] demostraron que una versión vectorizada de popcount64b puede ejecutarse más rápido que las instrucciones dedicadas (por ejemplo, popcnt en los procesadores x64).
Peso mínimo
En código de corrección de errores, el peso de Hamming mínimo, comúnmente denominado peso mínimowmin de un código es el peso de la palabra de código distinta de cero de menor peso. El peso w de una palabra de código es el número de unos en la palabra. Por ejemplo, la palabra 11001010 tiene un peso de 4.
En un códigos de bloque el peso mínimo es también la distancia de Hamming (dmin) y define la capacidad de corrección de errores del código. Si wmin = n, entonces (dmin = n) y el código corregirá hasta (dmin/2) errores.[16]
Lenguajes de programación que disponen de conteo de unos
Algunos compiladores de C proporcionan funciones intrínsecas que brindan funciones de conteo de bits. Por ejemplo, GCC (desde la versión 3.4 en abril de 2004) incluye una función integrada __builtin_popcount que utilizará una instrucción de procesador si está disponible o una aplicación de biblioteca eficiente en caso contrario.[17] LLVM-GCC ya incluía esta función desde la versión 1.5 en junio de 2005.[18]
En la Standard Template Library, la estructura de datos de matriz de bits bitset tiene un método count() que cuenta el número de bits que se establecen. En C++20 se agregó un nuevo encabezado <bit> que contiene las funciones std::popcount y std::has_single_bit, tomando argumentos de tipos enteros sin signo.
En Java, la estructura de datos de matriz de bits ampliable BitSet tiene un método BitSet.cardinality() que cuenta el número de bits que se establecen. Además, existen funciones Integer.bitCount(int) y Long.bitCount(long) para contar bits en enteros primitivos de 32 y 64 bits, respectivamente. Además, la clase de enteros de precisión arbitraria BigInteger también tiene un método BigInteger.bitCount() que cuenta bits.
En Python, el tipo int tiene un método bit_count() para contar el número de bits establecidos. Esta funcionalidad se introdujo en Python 3.10, lanzado en octubre de 2021.[19]
En Common Lisp, la función logcount, dado un número entero no negativo, devuelve el número de bits que son 1 (para enteros negativos, devuelve el número de bits que son 0 en notación de complemento a 2). En cualquier caso, el entero puede ser BIGNUM.
A partir de GHC 7.4, el paquete base Haskell tiene una función popCount disponible en todos los tipos que son instancias de la clase Bits (disponible en el módulo Data.Bits).[20]
La versión MySQL del lenguaje SQL proporciona BIT_COUNT() como una función estándar.[21]
Fortran dispone de la función elemental estándar e intrínseca popcnt, que devuelve el número de bits distintos de cero dentro de un entero (o matriz de enteros).[22]
Algunas calculadoras de bolsillo científicas programables cuentan con comandos especiales para calcular el número de bits establecidos, como por ejemplo #B en la HP-16C[6][23] y WP 43S,[24][25] #BITS[26][27] o BITSUM[28][29] en emuladores HP-16C y nBITS en WP 34S.[30][31]
Free Pascal implementa la orden popcnt desde la versión 3.0.[32]
Compatibilidad con procesadores
La computadora IBM 7030 en la década de 1960 calculaba el número de bits establecidos, así como el número de ceros a la izquierda como subproducto de todas las operaciones lógicas.[4]
Las máquinas de las series 6000 y Cyber 70/170 de Control Data Corporation (CDC) incluían una instrucción de conteo de población; en el modelo COMPASS esta instrucción se codificó como CXi .
La arquitectura Sun SPARC versión 9 de 64 bits definió una instrucción POPC,[12][4], pero la mayoría de las sistemas implantados no disponen de ella, lo que requiere que el sistema operativo la emule.[33]
La computadora MMIX de Donald Knuth, diseñada para reemplazar al modelo MIX, se menciona en su libro The Art of Computer Programming que tiene una instrucción SADD desde 1999. SADD a,b,c cuenta todos los bits que son 1 en b y 0 en c y escribe el resultado en a.
El Alpha 21264 de Compaq, lanzado en 1999, fue el primer diseño de CPU de la serie Alpha que tenía la extensión de conteo (CIX ).
Los procesadores Blackfin de Analog Devices cuentan con la instrucción ONES para realizar un conteo de población de 32 bits.[34]
La arquitectura Barcelona de AMD introdujo la manipulación avanzada de bits (ABM) ISA al incorporar la instrucción POPCNT como parte de las extensiones SSE4 en 2007.
Los procesadores Intel Core introdujeron una instrucción POPCNT con la extensión SSE4 del conjunto de instrucciones, disponible por primera vez en un procesador Nehalem basado en el Core i7, lanzado en noviembre de 2008.
↑Thompson, Thomas M. (1983). From Error-Correcting Codes through Sphere Packings to Simple Groups. The Carus Mathematical Monographs #21. Mathematical Association of America. p. 33.
↑Cohen, Gérard D.; Lobstein, Antoine; Naccache, David; Zémor, Gilles (1998). «How to improve an exponentiation black-box». En Nyberg, Kaisa, ed. Advances in Cryptology – EUROCRYPT '98, International Conference on the Theory and Application of Cryptographic Techniques, Espoo, Finland, May 31 – June 4, 1998, Proceeding. Lecture Notes in Computer Science 1403. Springer. pp. 211-220. doi:10.1007/BFb0054128.
↑Stoica, I.; Morris, R.; Liben-Nowell, D.; Karger, D. R.; Kaashoek, M. F.; Dabek, F.; Balakrishnan, H. (February 2003). «Chord: a scalable peer-to-peer lookup protocol for internet applications». IEEE/ACM Transactions on Networking11 (1): 17-32. S2CID221276912. doi:10.1109/TNET.2002.808407. «Section 6.3: "In general, the number of fingers we need to follow will be the number of ones in the binary representation of the distance from node to query."».
↑ abSPARC International, Inc. (1992). «A.41: Population Count. Programming Note». The SPARC architecture manual: version 8 (Version 8 edición). Englewood Cliffs, New Jersey, USA: Prentice Hall. pp. 231. ISBN0-13-825001-4.
↑Schwartz, Jake; Grevelle, Rick (2003-10-20 (1ª Ed. 1993)). HP16C Emulator Library for the HP48S/SX. 1.20 (1 edición). Consultado el 15 de agosto de 2015. (Nota: esta biblioteca también funciona en HP48 (066)/GX/G+. Más allá del conjunto de funciones de HP-16C, este paquete también admite cálculos para coma flotante binarios, octales y hexadecimales en notación científica, además de los números decimales de coma flotante habituales.)
↑Martin, Ángel M.; McClure, Greg J. (5 de septiembre de 2015). «HP16C Emulator Module for the HP-41CX - User's Manual and QRG». Archivado desde el original el 27 de abril de 2017. Consultado el 27 de abril de 2017. (Nota: más allá del conjunto de funciones HP-16C, esta biblioteca personalizada para HP-41 amplía la funcionalidad de la calculadora en unas 50 funciones adicionales.)