- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
是否有 MurMurHash 3 的 Delphi 实现?我尝试自己实现它,但我的实现实际上比 MurMurHash2 慢。 。正常吗?还有其他实现吗?
这是我的:
function MurMur3_32(const S: AnsiString; const Seed: LongWord=$9747b28c): LongWord;
const
c1 = $cc9e2d51;
c2 = $1b873593;
r1 = 15;
r2 = 13;
m = 5;
n = $e6546b64;
var
hash: LongWord;
len: LongWord;
k, k2: LongWord;
data: Integer;
begin
Hash := Seed;
len := Length(S);
//The default seed, $9747b28c, is from the original C library
// Initialize the hash to a 'random' value
hash := seed xor len;
// Mix 4 bytes at a time into the hash
data := 1;
while(len >= 4) do
begin
k := PLongWord(@S[data])^;
k := k*c1;
k := (k shl r1) or (k shr (32 - r1));
k := k*c2;
hash := hash xor k;
hash := ((hash shl r2) or (hash shr (32 - r2))) * m + n;
Inc(Data, 4);
Dec(len, 4);
end;
k2 := 0;
{ Handle the last few bytes of the input array
S: ... $69 $18 $2f
}
Assert(len <= 3);
if len = 3 then
k2 := k2 xor (LongWord(s[data+2]) shl 16);
if len >= 2 then
k2 := k2 xor (LongWord(s[data+1]) shl 8);
if len >= 1 then
begin
k2 := k2 xor (LongWord(s[data]));
k2 := k2 * c1;
k2 := (k2 shl r1) or (k2 shr (32 - r1));
k2 := k2 * c2;
hash := hash xor k2;
end;
// Do a few final mixes of the hash to ensure the last few
// bytes are well-incorporated.
len := Length(S);
hash := hash xor len;
hash := hash xor (hash shr 16);
hash := hash * $85ebca6b;
hash := hash xor (hash shr 13);
hash := hash * $c2b2ae35;
hash := hash xor (hash shr 16);
Result := hash;
end;
免责声明:我不知道Seed
值是否正确。
最佳答案
我的 FastDefaults 单元中有一个 murmurhash3 实现,地址为 https://github.com/JBontes/FastCode
这是 Murmurhash3 的源代码:
{$pointermath on}
function MurmurHash3(const [ref] HashData; Len: integer; Seed: integer = 0): integer;
const
c1 = $CC9E2D51;
c2 = $1B873593;
r1 = 15;
r2 = 13;
m = 5;
n = $E6546B64;
f1 = $85EBCA6B;
f2 = $C2B2AE35;
{$IFDEF purepascal}
var
i, Len2: integer;
k: cardinal;
remaining: cardinal;
Data: PCardinal;
label
case1, case2, case3, final;
begin
Result:= Seed;
Data:= @HashData;
for i:= 0 to (Len shr 2) - 1 do begin
k:= Data[i];
k:= k * c1;
k:= (k shl r1) or (k shr (32 - r1));
k:= k * c2;
Result:= Result xor k;
Result:= (Result shl r2) or (Result shr (32 - r2));
Result:= Result * m + n;
end; {for i}
Len2:= Len;
remaining:= 0;
case Len and $3 of
1: goto case1;
2: goto case2;
3: goto case3;
else goto final;
end;
case3:
dec(Len2);
inc(remaining, PByte(Data)[Len2] shl 16);
case2:
dec(Len2);
inc(remaining, PByte(Data)[Len2] shl 8);
case1:
dec(Len2);
inc(remaining, PByte(Data)[Len2]);
remaining:= remaining * c1;
remaining:= (remaining shl r1) or (remaining shr (32 - r1));
remaining:= remaining * c2;
Result:= Result xor remaining;
final:
Result:= Result xor Len;
Result:= Result xor (Result shr 16);
Result:= Result * f1;
Result:= Result xor (Result shr 13);
Result:= Result * f2;
Result:= Result xor (Result shr 16);
end;
{$ELSE}
{$REGION 'asm'}
{$IFDEF CPUx86}
asm
push EBX
push EDI
push ESI
xchg ECX,EDX
//EAX = data
//ECX = count in bytes
//EDX = seed
mov ESI,ECX
shr ECX,2
jz @remaining_bytes
@loop:
mov EDI,[EAX]
imul EDI,EDI,c1
rol EDI,r1
imul EDI,EDI,c2
xor EDX,EDI
rol EDX,r2
lea EDX,[EDX*4+EDX+n]
lea EAX,[EAX+4]
dec ECX
jnz @loop
@remaining_bytes:
mov ECX,ESI
and ECX,$3
jz @finalization
xor EBX,EBX
dec ECX
mov BL,byte ptr [EAX+ECX]
jz @process_remaining
shl EBX,8
dec ECX
mov BL,byte ptr [EAX+ECX]
jz @process_remaining
shl EBX,8
mov BL,byte ptr [EAX]
@process_remaining:
imul EBX,EBX,c1
rol EBX,r1
imul EBX,EBX,c2
xor EDX,EBX
@finalization:
xor EDX,ESI
mov EAX,EDX
shr EDX,16
xor EDX,EAX
imul EDX,EDX,f1
mov EAX,EDX
shr EDX,13
xor EDX,EAX
imul EDX,EDX,f2
mov EAX,EDX
shr EDX,16
xor EAX,EDX
pop ESI
pop EDI
pop EBX
end;
{$ENDIF}
{$IFDEF CPUx64}
asm
push RBX
push RDI
push RSI
mov RAX,RCX
mov RCX,RDX
mov RDX,R8
//RAX = data
//RCX = count in bytes
//RDX = seed
mov ESI,ECX
shr ECX,2
jz @remaining_bytes
@loop:
mov EDI, dword ptr [RAX]
imul EDI,EDI,c1
rol EDI,r1
imul EDI,EDI,c2
xor EDX,EDI
rol EDX,r2
lea EDX,dword ptr [EDX*4+EDX+n] // *5 + n
lea RAX,qword ptr [RAX+4]
dec ECX
jnz @loop
@remaining_bytes:
mov ECX,ESI
and ECX,$3
jz @finalization
xor RBX,RBX
dec ECX
mov BL,byte ptr [RAX+RCX]
jz @process_remaining
shl EBX,8
dec ECX
mov BL,byte ptr [RAX+RCX]
jz @process_remaining
shl EBX,8
mov BL,byte ptr [RAX]
@process_remaining:
imul EBX,EBX,c1
rol EBX,r1
imul EBX,EBX,c2
xor EDX,EBX
@finalization:
xor EDX,ESI
mov EAX,EDX
shr EDX,16
xor EDX,EAX
imul EDX,EDX,f1
mov EAX,EDX
shr EDX,13
xor EDX,EAX
imul EDX,EDX,f2
mov EAX,EDX
shr EDX,16
xor EAX,EDX
pop RSI
pop RDI
pop RBX
end;
{$ENDIF}
{$ENDREGION}
{$ENDIF}
goto 的位置是为了模拟 C 的fallthough switch/case 语句。
这种代码在asm中更容易编写,它比Delphi生成的asm具有更好的寄存器使用率。
为什么你的代码很慢
我唯一能看到问题的地方是这里:
Project42.dpr.54: while(len >= 4) do //a for loop is faster.
00420E17 83FE04 cmp esi,$04
00420E1A 7242 jb $00420e5e
//This translates into inefficient code
Project42.dpr.56: k := PLongWord(@S[data])^;
00420E1C 8B0424 mov eax,[esp]
00420E1F 8D4438FF lea eax,[eax+edi-$01]
00420E23 8B00 mov eax,[eax]
三个间接内存引用和 read is misaligned !!
请参阅此处了解更多信息:Purpose of memory alignment 不要介意接受的答案,请参阅第二个答案。
双字的读取应该始终发生在双字边界上。@pointer^
技巧使编译器添加额外的间接级别(以及额外的内存往返(糟糕))。
使用{$pointermath on}
并将指针作为数组寻址。
整数!=指针
使用integer
来存储指针也是错误的。
它会在 X64 中崩溃。 改用 NativeUInt。
我的版本中的等效代码翻译为:
Project42.dpr.128: Data:= @HashData;
00420FCD 89442404 mov [esp+$04],eax
Project42.dpr.129: for i:= 0 to (Len shr 2) - 1 do begin
00420FD1 8B1C24 mov ebx,[esp]
00420FD4 C1EB02 shr ebx,$02
00420FD7 4B dec ebx
00420FD8 85DB test ebx,ebx
00420FDA 7C3E jl $0042101a
00420FDC 43 inc ebx
00420FDD 33D2 xor edx,edx
////------------------------------------------///
Project42.dpr.130: k:= Data[i];
00420FDF 8B442404 mov eax,[esp+$04]
00420FE3 8B0490 mov eax,[eax+edx*4]
请注意,
不少
不需要的间接内存引用,并且读取已正确对齐。
当然asm版本稍微好一些,但是asm和pascal版本之间的差异应该小于两个Pascal版本之间的差异。
这就是我认为你的表现被浪费的地方。
未对齐的读取消耗了 X86 上的大量(浪费的)周期。
在其他处理器上,速度下降甚至更严重。
代码的其他问题
将您的实现限制为字符串是一件坏事。
如果我想对记录进行哈希处理怎么办?
不要将二进制数据强制转换为字符串。
字符串不适合二进制数据。
只需使用无类型参数和指针。
种子值
我认为不存在正确的种子值。据我了解,种子就在那里,因此您可以链接调用 Murmurhash。
您使用第一个哈希的输出作为第二次运行的种子。
这样您就可以输入 2 个变量并获得相同的输出,就像一次性处理这两个变量一样。
让我知道它们对您的代码的执行情况。
关于delphi - 有 MurMurHash3 的 Delphi 实现吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30942918/
我正在使用 C/C++ 中的 murmurhash 函数,就像这里建议的那样:https://sites.google.com/site/murmurhash/ (MurmurHash2.cpp)。我
我用 Murmur hash 对 800 000 个字符串值进行哈希处理,这导致了很多冲突(冲突),大约有 17 个冲突(不同的字符串给出相同的哈希值),这是否正常,任何人都知道 murmur has
我一直在努力深入了解 MurmurHash 是什么做。 我已经阅读了基本说明,但还没有找到关于何时使用它以及为什么使用它的良好解释。我知道它非常快,但想了解更多。 我问了一个相关的question关于
我正在查看 MurmurHash (sites.google.com/site/murmurhash/)我正在以一种黑盒子的方式使用它,而不是在这个阶段试图理解数学。 但是,我确实稍微看了一下代码并且
在 Scala 2.10 中,MurmurHash 由于某种原因已被弃用,说我现在应该使用 MurmurHash3。但 API 不同,MurmurHash3 没有有用的 scaladocs -> 失败
我正在用 C 语言实现散列表和散列函数,听说 Murmurhash 是适合此目的的快速算法。为此提供的查找一些 C 代码: uint32_t murmur3_32(const char *key, u
我需要(但找不到)MurmurHash 的纯 python(无 c++)实现,我太新手了,不能自己写。速度或内存使用对我的项目来说并不重要。 我找到了一个尝试 here ,但它仅限于 31 位散列,我
我需要使用 murmurhash 对 NSString 进行哈希处理我被迫这样做,因为其他团队正在这样做,我需要在 x86 平台上使用 64 位 key 长度,有人在 objective-C 中实现或
我正在使用 SBT 0.13.2(也可以是 0.13.5),并且正在尝试为 2.10 编写一个项目并将其交叉编译为 2.9 和 2.10。它使用 scala.util.hashing.MurmurHa
编辑:请参阅评论以获取正确答案。 大家好,我在安装 NLP 程序 SpaCY 时遇到了一个问题。 我尝试了 pip install -U spacy 和 pip install spacy,但我似乎遇
我正在尝试使用 MurmurHash(在 64 位计算机上返回 64 位哈希值)并已将简单的 3 个字母字符串“yes”发送给它,如下所示 char* charptr = "yes"; cout *
Haskell 和 Python 似乎不同意 Murmurhash2 结果。 Python、Java 和 PHP 返回相同的结果,但 Haskell 没有。关于 Haskell 上的 Murmurha
我正在编写一个 BloomFilter 并想使用 Scala 的默认 MurmurHash3 实现:scala.util.MurmurHash3。我的编译失败,但是出现以下编译错误: [error]
查看使用接受字符串并返回 64 位带符号整数值的哈希算法。 它不必在密码学上是可靠的,只要提供一个合适的冲突率就可以用作分布式存储的 key 。 我在看 murmur hash that seems
我是一名优秀的程序员,十分优秀!