提高Crc16计算的速度

时间:2010-09-28 07:17:45

标签: delphi delphi-2010 crc

我需要在大文件上用$ 1021多项式计算Crc16校验和,下面是我当前的实现,但是对于大文件来说相当慢(例如90 MB文件大约需要9秒)。

所以我的问题是如何改进我当前的实现(使其更快),我用Google搜索并查看了一些实现表查找的示例但我的问题是我不明白如何修改它们以包含多项式(可能我的数学失败了。)

{ based on http://miscel.dk/MiscEl/CRCcalculations.html }
function Crc16(const Buffer: PByte; const BufSize: Int64;
  const Polynom: WORD=$1021; const Seed: WORD=0): Word;
var
  i,j: Integer;
begin
  Result := Seed;

  for i:=0 to BufSize-1 do
  begin
    Result := Result xor (Buffer[i] shl 8);

    for j:=0 to 7 do begin
      if (Result and $8000) <> 0 then
        Result := (Result shl 1) xor Polynom
      else Result := Result shl 1;
    end;
  end;

  Result := Result and $FFFF;
end;

4 个答案:

答案 0 :(得分:6)

如果您希望快速,则需要实现表查找CRC算法。

A PAINLESS GUIDE TO CRC ERROR DETECTION ALGORITHMS INDEX V3.00 (9/24/96)

的第10章

答案 1 :(得分:2)

您的Result变量是Word,这意味着在进入内循环时可能有64k个可能的值。计算循环可能生成的64k可能结果并将它们存储在数组中。然后,不是为输入缓冲区的每个字节循环八次,而只需查找数组中校验和的下一个值。像这样:

function Crc16(const Buffer: PByte; const BufSize: Int64;
  const Polynom: Word = $1021; const Seed: Word = 0): Word;
{$J+}
const
  Results: array of Word = nil;
  OldPolynom: Word = 0;
{$J-}
var
  i, j: Integer;
begin
  if (Polynom <> OldPolynom) or not Assigned(Results) then begin
    SetLength(Results, 65535);
    for i := 0 to Pred(Length(Results)) do begin
      Results[i] := i;
      for j := 0 to 7 do
        if (Results[i] and $8000) <> 0 then
          Results[i] := (Results[i] shl 1) xor Polynom
        else
          Results[i] := Results[i] shl 1;
    end;
    OldPolynom := Polynom;
  end;

  Result := Seed;
  for i := 0 to Pred(BufSize) do
    Result := Results[Result xor (Buffer[i] shl 8)];
end;

该代码会在Polynom更改时重新计算查找表。如果该参数在一组值之间变化,那么考虑缓存为它们生成的查找表,这样就不会浪费时间重复计算相同的表。

如果Polynom 总是为1021美元,那么请不要为它添加参数。事先计算所有64k值并将它们硬编码成一个大数组,这样你的整个函数就减少到我上面函数的最后三行。

答案 2 :(得分:2)

从Jedi代码库的jclMath.pas单元中查找CRC例程。它使用CRC查找表。

http://jcl.svn.sourceforge.net/viewvc/jcl/trunk/jcl/source/common/

答案 3 :(得分:1)

旧线程,我知道。这是我的实现(只有一个循环):

function crc16( s : string; bSumPos : Boolean = FALSE ) : Word;
var
 L, crc, sum, i, x, j : Word;

begin
  Result:=0;
  L:=length(s);
  if( L > 0 ) then
   begin
    crc:=$FFFF;
    sum:=length(s);
    for i:=1 to L do
    begin
            j:=ord(s[i]); 
            sum:=sum+((i) * j);
            x:=((crc shr 8) xor j) and $FF;
            x:=x xor (x shr 4);
            crc:=((crc shl 8) xor (x shl 12) xor (x shl 5) xor x) and $FFFF;
    end;
    Result:=crc+(Byte(bSumPos) * sum);
   end;
end;

不错的是,您可以使用它创建唯一的ID,例如获取文件名的唯一标识符,例如:

function uniqueId( s : string ) : Word;
begin
 Result:=crc16( s, TRUE );
end;

干杯, Erwin Haantjes