Solución:
Python 2 (a diferencia de py3) está haciendo un CRC firmado de 32 bits.
Esos sitios están haciendo un CRC de 32 bits sin firmar.
De lo contrario, los valores son los mismos, como puede ver en esto:
>>> 0x100000000 - 0xb1d4025b == 0x4e2bfda5
True
Una forma rápida de convertir de 32 bits con signo a 32 bits sin firmar es:*
>>> -1311505829 % (1<<32)
2983461467
O, en hexadecimal:
>>> hex(-1311505829 % (1<<32))
'0xb1d4025b'
& 0xFFFFFFFF
o % 0x100000000
o & (2**32-1)
o % (2**32)
y así sucesivamente son todas formas equivalentes de hacer el mismo juego de bits; simplemente se reduce a cuál le resulta más legible.
* Esto solo funciona en lenguajes que hacen división de enteros en el suelo, como Python (-3 // 2 == -2
); en lenguajes que hacen división entera truncada, como Java (-3 / 2 == -1
), aún terminará con un número negativo. Y en los lenguajes que ni siquiera requieren que la división y el mod vayan juntos correctamente, como C, todas las apuestas están desactivadas, pero en C, simplemente enviarías los bytes al tipo que desees …
La documentación de zlib.crc32 sugiere usar el siguiente enfoque “para generar el mismo valor numérico en todas las versiones y plataformas de Python”.
import zlib
hex(zlib.crc32(b'hello-world') & 0xffffffff)
El resultado es 0xb1d4025b
como se esperaba.
Parece que Python devuelve un entero con signo (de ahí el número negativo), mientras que los demás devuelven un entero sin signo.
Intenté usar un módulo con 2 ^ 32 y me dio el mismo valor que estos sitios.
>>> hex(zlib.crc32(b'hello-world')% 2**32)
'0xb1d4025b'