Обчисліть хеш CRC32


14

Кредити

Цей виклик походить від @miles .


Створіть функцію, яка обчислює хеш CRC32 вхідного рядка. Вхід буде рядком ASCII будь-якої довжини. Виведенням буде хеш CRC32 цього вхідного рядка.

Пояснення

Алгоритм CRC32 та інших CRC по суті однаковий, тому тут буде продемонстровано лише CRC3.

По-перше, у вас є поліном генератора, який насправді є 4-розрядним [n + 1] цілим числом (було б 33-бітним в CRC32).

У цьому прикладі многочлен генератора є 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 дорівнює нулю, що є 001результатом хешу CRC3.

Технічні характеристики

  • Поліномом генератора є 0x104C11DB7, або 0b100000100110000010001110110110111, або 4374732215.
  • Введенням може бути рядок або список цілих чисел, або будь-який інший розумний формат.
  • Виведенням буде шістнадцятковий рядок або просто ціле число, або будь-який інший розумний формат.
  • Вбудовані модулі, які обчислюють хеш CRC32, не дозволені.

Мета

Діють стандартні правила для .

Виграє найкоротший код.

Тестові справи

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

Якщо я правильно розумію, це робимо модуль 2 поліноміального поділу і знаходимо залишок, тобто аналог моди в множенні XOR .
xnor

1
Так. Це не модуль xnor, хоча це xor modulo.
Лина монашка

Для CRC32 ви спочатку додаєте 31 0?
xnor

Так - - - - - - - - -
Лина монашка

1
@KennyLau ви можете пінг людей з їх іменем, як і в чаті.
Rɪᴋᴇʀ

Відповіді:


12

Intel x86, 34 30 29 27 байт

Приймає адресу нульового завершеного рядка в ESI і повертає CRC в EBX:

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

Включення пропозицій від Пітера Кордеса, щоб зберегти ще чотири байти. Це передбачає умову виклику, де прапор напряму для рядкових інструкцій очищається при введенні.

Включення пропозиції Пітера Феррі використовувати push literal і pop для завантаження константи, економлячи один байт.

Включаючи пропозицію Пітера Феррі перейти до другого байту xorl %eax, %ebxінструкції, яка є retlінструкцією, в поєднанні зі зміною інтерфейсу підпрограми, щоб взяти нульовий завершений рядок замість довжини, заощадивши два байти.


Використовуйте конвенцію про дзвінки, яка вимагає, щоб прапор напряму був очищений під час входу, щоб ви могли зберегти cldінн (як я це зробив у своїй відповіді adler32 ). Чи нормальна практика допускати абсолютно довільні умовні вимоги для відповідей на асм?
Пітер Кордес

У будь-якому випадку, схоже, що ваш код буде працювати як машинний код x86-64, і ви можете скористатися умовою виклику x86-64 SysV x32, щоб взяти підрахунок ediі вказівник esi(можливо, не розширений нулем, тому, можливо, підробляйте речі та вимагайте 64-бітний нульовий розширений покажчик). (x32, тож ви можете безпечно використовувати математику 32-бітового покажчика, але все ще маєте конвенцію про виклик аргументів. Оскільки ви не користуєтесь inc, у довгому режимі немає недоліків.)
Пітер Кордес

Чи розглядали ви, як дотримуватися edxбайтового порядку? bswap edxстановить лише 2B. shr %edxдорівнює 2В, те саме, що і зсув вліво add %edx,%edx. Це, мабуть, не корисно; Якщо це не дає більшої оптимізації, ви економите 3B для shl $24, %eax, але витрачаєте 4B xor %eax,%eaxна початку та bswap %edxв кінці. Нульовий еакс дозволяє вам використовувати cdqнуль %edx, тому загалом це миття. Хоча це буде краще: це дозволяє уникнути часткового реєстрування / уповільнення кожної ітерації від написання, alа потім читання eaxз допомогою SHL. : P
Пітер Кордес

1
Поплутався з питанням Adler-32, яке має обмеження тривалості. Це питання не має явного обмеження тривалості.
Марк Адлер

1
Можливо, є спосіб скоротити це за допомогою інструкції PCLMULQDQ. Однак для його використання, як правило, потрібно багато констант, тому, можливо, ні.
Марк Адлер


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, заміщення вводу нулями та вирівнювання полінома з найбільш значущою двійковою цифрою робить цей підхід, який використовує списки бітів замість цього, в рази коротший.

ḅ⁹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 Це дуже розумно, не соромтеся зробити це окремою відповіддю. :)
Мартін Ендер

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

JavaScript (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.
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.