2009-12-22 7 views
9

Busco una función Perl cadena de suma de comprobación con las siguientes propiedades:Una función de cadena suma de comprobación rápida de los valores de generación de Perl en el rango 0..2^32-1

  • de entrada: cadena Unicode de indefinido longitud ($string)
  • de salida: número entero sin signo ($hash), para lo cual 0 <= $hash <= 2^32-1 bodegas (0 a 4,294,967,295, que corresponde al tamaño de un 4-byte MySQL unsigned int)

Pseudo-código:

sub checksum { 
    my $string = shift; 
    my $hash; 
    ... checksum logic goes here ... 
    die unless ($hash >= 0); 
    die unless ($hash <= 4_294_967_295); 
    return $hash; 
} 

Idealmente la función de suma de control debe ser rápido para funcionar y debe generar valores algo de manera uniforme en el espacio objetivo (0 .. 2^32-1) para evitar colisiones. En esta aplicación, las colisiones aleatorias son totalmente no fatales, pero obviamente quiero evitarlas en la medida de lo posible.

Teniendo en cuenta estos requisitos, ¿cuál es la mejor manera de resolver esto?

+0

¿Quieres evitar las colisiones con todas las secuencias posibles, pero sólo tienen un 4 mil millones posible digiere? ¿Por qué es importante usar un número entero? ¿Qué tal si usamos algo como MD5, incluso si tiene que almacenar el resumen como una cadena? –

+1

"Desea evitar colisiones con todas las cadenas posibles" - No, como se indica en la pregunta, simplemente "quiero evitarlas en la medida de lo posible". – knorv

+0

"¿Por qué es importante usar un número entero?" - Como se indica en la pregunta, la suma de comprobación se almacenará en "un MySQL de 4 bytes sin firmar int". – knorv

Respuesta

11

Cualquier función hash será suficiente - simplemente trunquela a 4 bytes y conviértala en un número. Las buenas funciones hash tienen una distribución aleatoria, y esta distribución será constante sin importar dónde trunque la cadena.

Sugiero Digest::MD5 porque es la implementación de hash más rápida que viene con Perl como estándar. String :: CRC, como menciona Pim, también se implementa en C y debería ser más rápido.

continuación se explica cómo calcular el hash y convertirlo en un entero:

use Digest::MD5 qw(md5); 
my $str = substr(md5("String-to-hash"), 0, 4); 
print unpack('L', $str); # Convert to 4-byte integer (long) 
+1

B :: hash también viene con núcleo perl, utiliza la función hash interna del núcleo, es más rápido que MD5 y devuelve un entero hexadecimal de 32 bits. Pero no tan seguro como MD5. – rurban

3

De perldoc -f unpack:

 For example, the following computes the same number as the 
     System V sum program: 

      $checksum = do { 
       local $/; # slurp! 
       unpack("%32W*",<>) % 65535; 
      }; 
+0

Esta suma de 32 bits de todos los bits es un valor hash muy malo para las distribuciones aleatorias. Cualquier función hash es mejor, incluso las más simples. – rurban

+0

Claro, pero ese es el mismo problema que tiene el programa System V 'sum'. Ver el párrafo. ¿O estás argumentando que 'sum' está discutiblemente roto? En ese caso, no se trata de Perl. –

+0

'sum' es lo más rápido que obtendrá, aunque como se indicó anteriormente, no es demasiado robusto. Puedes mejorarlo ligeramente usando el tamaño, p. '$ _ = <>; desempaquetar ("% 32W *", $ _)% 65535. longitud ($ _) '. Todo lo que necesite ser más robusto debería usar 'Digest :: MD5' o' Digest :: SHA', etc. –

Cuestiones relacionadas