CRC32 해시 계산


14

크레딧

이 도전은 @miles 에서 시작되었습니다 .


입력 문자열의 CRC32 해시를 계산하는 함수를 작성하십시오. 입력은 모든 길이의 ASCII 문자열이됩니다. 출력은 해당 입력 문자열의 CRC32 해시입니다.

설명

CRC32와 다른 CRC의 알고리즘은 본질적으로 동일하므로 여기서는 CRC3 만 설명합니다.

먼저, 생성기 다항식이 있는데, 실제로 4 비트 [n + 1] 정수 (CRC32에서는 33 비트)입니다.

이 예에서 생성기 다항식은 1101입니다.

그런 다음이 예제에서는 해시 될 문자열을 갖게됩니다 00010010111100101011001101.

00010010111100101011001101|000 (1)    append three [n] "0"s
   1101                        (2)    align with highest bit
00001000111100101011001101|000 (3)    XOR (1) and (2)
    1101                       (4)    align with highest bit
00000101111100101011001101|000 (5)    XOR (3) and (4)
     1101                      (6)    align with highest bit
00000011011100101011001101|000 (7)    XOR (5) and (6)
      1101                     (8)    align with highest bit
00000000001100101011001101|000 (9)    XOR (7) and (8)
          1101                 (10)   align with highest bit
00000000000001101011001101|000 (11)   XOR (9) and (10)
             1101              (12)   align with highest bit
00000000000000000011001101|000 (13)   XOR (11) and (12)
                  1101         (14)   align with highest bit
00000000000000000000011101|000 (15)   XOR (13) and (14)
                     1101      (16)   align with highest bit
00000000000000000000000111|000 (17)   XOR (15) and (16)
                       110 1   (18)   align with highest bit
00000000000000000000000001|100 (19)   XOR (17) and (18)
                         1 101 (20)   align with highest bit
00000000000000000000000000|001 (21)   XOR (19) and (20)
^--------REGION 1--------^ ^2^

(21)영역 1이 0 일 때에 얻은 나머지 001는 CRC3 해시의 결과입니다.

명세서

  • 생성기 다항식은 0x104C11DB7, 또는 0b100000100110000010001110110110111, 또는 4374732215입니다.
  • 입력은 문자열 또는 정수 목록 또는 다른 적절한 형식 일 수 있습니다.
  • 출력은 16 진 문자열 또는 정수 또는 다른 적절한 형식입니다.
  • CRC32 해시를 계산하는 내장 기능은 허용되지 않습니다.

대한 표준 규칙이 적용됩니다.

가장 짧은 코드가 승리합니다.

테스트 사례

input         output      (hex)
"code-golf"   147743960   08CE64D8
"jelly"       1699969158  65537886
""            0           00000000

내가 올바르게 이해한다면, 이것은 다항식 나눗셈 모듈로 2를하고 나머지, 즉 XOR 곱셈 에서 mod의 유사체를 찾는 것 입니다.
xnor

1
네. 이것은 xnor 모듈로가 아니지만 xor 모듈로입니다.
Leaky Nun

CRC32의 경우 먼저 31 0을 추가합니까?
xnor

예 – – – – – – – – – –
새기다 수

1
@KennyLau 채팅처럼 이름으로 사람들을 핑 (Ping) 할 수 있습니다.
Rɪᴋᴇʀ

답변:


12

인텔 x86, 34 30 29 27 바이트

ESI에서 0으로 끝나는 문자열의 주소를 받아서 EBX에서 CRC를 반환합니다.

31 db ac c1 e0 18 74 01 31 c3 6a 08 59 01 db 73 
06 81 f3 b7 1d c1 04 e2 f4 eb e7

분해 (AT & T 구문) :

00000000    xorl    %ebx, %ebx
00000002    lodsb   (%esi), %al
00000003    shll    $24, %eax
00000006    je      0x9
00000008    xorl    %eax, %ebx
0000000a    pushl   $8
0000000c    popl    %ecx
0000000d    addl    %ebx, %ebx
0000000f    jae     0x17
00000011    xorl    $0x4c11db7, %ebx
00000017    loop    0xd
00000019    jmp     0x2
0000001b

Peter Cordes의 제안을 통합하여 4 바이트를 더 절약합니다. 이는 입력시 문자열 명령어의 방향 플래그가 지워지는 호출 규칙을 가정합니다.

Peter Ferrie가 push literal과 pop을 사용하여 상수를로드하고 1 바이트를 절약 할 것을 제안합니다.

Peter Ferrie의 제안을 통합하여 xorl %eax, %ebx명령 인 명령 의 두 번째 바이트로 건너 뛰는 retl대신 루틴의 인터페이스를 변경하여 길이 대신 0으로 끝나는 문자열을 가져와 총 2 바이트를 절약했습니다.


입력시 방향 플래그를 지워야하는 호출 규칙을 사용하여 cldinsn을 저장할 수 있습니다 ( adler32 answer에서했던 것처럼 ). asm 응답에 대해 완전히 임의의 호출 규칙을 허용하는 것이 일반적인 방법입니까?
Peter Cordes

어쨌든 코드가 x86-64 기계 코드로 작동하는 것처럼 보이며 x86-64 SysV x32 호출 규칙을 사용하여 카운트 인하 고 edi포인터 를 가져올 수 있습니다 esi(0 확장되지 않을 수 있으므로 일을 퍼지하지 않아도됩니다. 64 비트 제로 확장 포인터). (x32를 사용하면 32 비트 포인터 수학을 안전하게 사용할 수 있지만 여전히 register-args 호출 규칙을 사용할 수 있습니다.를 사용하지 않기 때문에 inc긴 모드에 대한 단점은 없습니다.)
Peter Cordes

edx바이트 역순으로 유지하는 것을 고려 했습니까 ? bswap edx단지 2B입니다. shr %edx의 왼쪽 시프트와 같은 2B입니다 add %edx,%edx. 이것은 아마도 도움이되지 않습니다. 더 많은 최적화가 가능하지 않으면에 대한 3B를 절약 shl $24, %eax하지만 xor %eax,%eax시작과 bswap %edx끝에 4B를 소비 합니다. 제로 eax를 사용 cdq하면 제로 를 사용할 수 %edx있으므로 전반적으로 세척입니다. 그러나 더 나은 성능을 발휘합니다 : 모든 반복에서 부분 레지스터 스톨 / 슬로우 다운이 shl로 쓰고 al읽히는 것을 피합니다 eax. : P
Peter Cordes

1
길이 제한이있는 Adler-32 질문과 혼동되었습니다. 이 질문에는 명시적인 길이 제한이 없습니다.
Mark Adler

1
PCLMULQDQ 명령으로이를 더 짧게 만드는 방법이있을 수 있습니다. 그러나 그 사용에는 많은 상수가 필요한 경향이 있으므로 가능하지는 않습니다.
Mark Adler


4

루비, 142 바이트

익명의 기능; 문자열을 입력으로 사용하고 정수를 반환합니다.

->s{z=8*i=s.size;r=0;h=4374732215<<z
l=->n{j=0;j+=1 while 0<n/=2;j}
s.bytes.map{|e|r+=e*256**(i-=1)};r<<=32
z.times{h/=2;r^=l[h]==l[r]?h:0}
r}

2
사람들이 우리를 구별 할 수 있도록 이름을 바꿀 수 있습니까? XD
Leaky Nun

2
@ KennyLau 당신은 너무 까다로워해야합니다 ... 괜찮아요
가치 잉크

난 그냥 xd 농담을했다
Leaky Nun

4

젤리 , 23 바이트

ḅ⁹Bµ4374732215B×ḢḊ^µL¡Ḅ

입력은 정수 목록 형식입니다. 온라인으로 사용해보십시오! 또는 모든 테스트 사례를 확인하십시오 .

작동 원리

Jelly에는 비트 단위 XOR이 있지만 입력을 0으로 채우고 다항식을 가장 중요한 이진수와 정렬하면 비트 목록을 대신 사용하는 것이 더 짧습니다.

ḅ⁹Bµ4374732215B×ḢḊ^µL¡Ḅ  Main link. Argument: A (list of bytes)

ḅ⁹                       Convert A from base 256 to integer.
  B                      Convert the result to binary, yielding a list.
   µ                     Begin a new, monadic chain. Argument: B (list of bits)
    4374732215B          Convert the integer to binary, yielding a list.
                Ḣ        Pop and yield the first, most significant bit of B.
               ×         Multiply each bit in the polynomial by the popped bit.
                 ^       Compute the element-wise XOR of both lists.
                         If one of the lists is shorter, the elements of the other
                         lists do not get modified, thus avoiding the necessity
                         of right-padding B with zeroes.
                  µ      Convert the previous chain into a link.
                   L¡    Execute the chain L times, where L is the number of bits
                         in the original bit list.
                     Ḅ   Convert from binary to integer.


3

CJam, 37 36 바이트

q256b32m<{Yb4374732215Yb.^Yb_Yb32>}g

여기에서 테스트하십시오.

설명

q               e# Read input.
256b            e# Convert to single number by treating the character codes
                e# as base-256 digits.
32m<            e# Left-shift the number by 32 bits, effectively appending 32
                e# zeros to the binary representation.
{               e# While the condition on top of the stack is truthy...
  Yb            e#   Convert the number to base 2.
  4374732215Yb  e#   Convert the polynomial to base 2.
  .^            e#   Take the bitwise XOR. If the number is longer than the
                e#   polynomial, the remaining bits will be left unchanged.
  Yb            e#   Convert the list back from base 2, effectively stripping
                e#   leading zeros for the next iteration.
  _             e#   Duplicate the result.
  Yb            e#   Convert back to base 2.
  32>           e#   Remove the first 32 bits. If any are left, continue the loop.
}g

q256bYb_,{(4374732215Ybf*1>.^}*Yb몇 바이트를 절약합니다.
데니스

@Dennis 정말 영리합니다. 별도의 답변을 주시기 바랍니다. :)
Martin Ender

3

Pyth, 28 바이트

uhS+GmxG.<C"Á·"dlhG.<Cz32

온라인으로 사용해보십시오 : 데모 또는 테스트 스위트

설명:

uhS+GmxG.<C"..."dlhG.<Cz32   implicit: z = input string
                      Cz     convert to number
                    .<  32   shift it by 32 bits
u                            apply the following expression to G = ^,
                             until it get stuck in a loop:
     m           lhG            map each d in range(0, log2(G+1)) to:
          C"..."                   convert this string to a number (4374732215)
        .<      d                  shift it by d bits
      xG                           xor with G
   +G                           add G to this list
 hS                             take the minimum as new G

2

자바 스크립트 (ES6), 180 바이트

f=(s,t=(s+`\0\0\0\0`).replace(/[^]/g,(c,i)=>(c.charCodeAt()+256*!!i).toString(2).slice(!!i)))=>t[32]?f(s,t.replace(/.(.{32})/,(_,m)=>(('0b'+m^79764919)>>>0).toString(2))):+('0b'+t)

33 비트 XOR 연산자가 없거나 심지어 부호없는 32 비트 XOR 연산자가 없으면 도움이되지 않습니다.


1

CJam, 33 바이트

q256bYb_,{(4374732215Ybf*1>.^}*Yb

입력은 문자열 형태입니다. 온라인으로 사용해보십시오!

작동 원리

q                                  Read all input from STDIN.
 256bYb                            Convert it from base 256 to base 2.
       _,{                   }*    Compute the length and repeat that many times:
          (                          Shift out the first bit.
           4374732215Yb              Convert the integer to base 2.
                       f*            Multiply each bit by the shifted out bit.
                         1>          Remove the first bit.
                           .^        Compute the element-wise XOR of both lists.
                                     If one of the lists is shorter, the elements
                                     of the other lists do not get modified, thus
                                     avoiding the necessity of right-padding B with
                                     zeroes.
                               Yb  Convert the final result from base 2 to integer.
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.