计算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为零时,在处获得的余数001将是CRC3哈希的结果。

眼镜

  • 生成多项式为0x104C11DB70b1000001001100000100011101101101114374732215
  • 输入可以是字符串或整数列表,或任何其他合理的格式。
  • 输出可以是十六进制字符串,也可以是整数,也可以是任何其他合理的格式。
  • 不允许使用用于计算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

是– – – – – – – – –
Leaky Nun

1
@KennyLau就像聊天一样,您可以用他们的名字ping通人。
Rɪᴋᴇʀ

Answers:


12

英特尔86,34 30 29 27个字节

在ESI中获取以零结尾的字符串的地址,并在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的建议以节省更多的四个字节。这假定了一个调用约定,其中在输入时清除了字符串指令的方向标志。

结合了Peter Ferrie的建议,即使用push字面量和pop来加载常量,从而节省了一个字节。

结合Peter Ferrie的建议跳转到xorl %eax, %ebx指令的第二个字节(即一条retl指令),并结合更改例程的接口以采用以零结尾的字符串代替长度,从而总共节省了两个字节。


使用要求在输入时清除方向标志的调用约定,以便您可以保存cldinsn(就像我在adler32 answer中所做的那样)。允许完全任意的调用约定获取asm答案是正常的做法吗?
彼得·科德斯

无论如何,看起来您的代码将可以用作x86-64机器代码,并且您可以使用x86-64 SysV x32调用约定来进行计数edi和输入指针esi(可能不是零扩展的,因此可能会弄乱东西并需要使用64位零扩展指针)。(x32,因此您可以安全地使用32位指针数学,但仍然具有register-args调用约定。由于您不使用inc,因此long模式没有不利之处。)
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,所以总的来说这很容易。不过,它会执行得更好:避免每次写入时部分寄存器的停顿/减速aleax使用shl和读取时。:P
彼得·科德斯

1
与Adler-32问题混淆,该问题有长度限制。这个问题没有明确的长度限制。
Mark Adler

1
可以使用PCLMULQDQ指令来缩短此时间。但是,它的使用往往需要很多常量,因此可能不需要。
Mark Adler


4

Ruby,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,但将输入填充零并使多项式与最高有效二进制数对齐会使该方法使用位列表,而不是tad。

ḅ⁹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.
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.