% 연산자를 사용하지 않고 잘 분산 된 해시 테이블을 구현할 수 있습니까?


11

C #에서 빠르고 잘 분산 된 해시 테이블을 구현하려고합니다. 임의의 해시 코드를 가져 와서 "제한"하여 해시를 인덱스하는 데 사용할 수있는 해시 제한 함수를 선택하는 데 문제가 있습니다. 지금까지 볼 수있는 두 가지 옵션이 있습니다.

  • 한편으로 버킷에 항상 소수의 요소가 있는지 확인하고 해시를 제한하기 위해 버킷 수로 간단하게 모듈화 할 수 있습니다. 사실 이것은 .NET 사전이하는 일 입니다. 이 접근법의 문제점은 % 사용이 다른 작업에 비해 매우 느리다는 것입니다. 당신이 보면 Agner 안개 명령 테이블 , idiv(%에 대해 생성됩니다 어셈블리 코드) 새로운 인텔 프로세서 ~ 25 사이클의 명령 대기 시간을 가지고있다. 약 3에 대한이를 비교하여 mul같은 비트 작전을 위해, 또는 1 and, or또는 xor.

  • 반면에 버킷 수는 항상 2의 거듭 제곱을 가질 수 있습니다. 해시의 계수를 계산해야하므로 배열 외부에서 색인을 생성하려고 시도하지 않지만 이번에는 비용이 덜 듭니다. . 2의 거듭 제곱 % N은 단지 & (N - 1)이므로, 제한은 1-2 사이클 만 소요되는 마스킹 작업으로 줄어 듭니다. 이것은 구글의 sparsehash에 의해 수행됩니다 . 이것의 단점은 좋은 해시를 제공하기 위해 사용자를 의지한다는 것입니다. 해시를 마스킹하면 해시의 일부가 차단되므로 해시의 모든 비트를 더 이상 고려하지 않습니다. 예를 들어, 사용자의 해시가 고르지 않게 분배되는 경우, 예를 들어 상위 비트 만 채워지거나 하위 비트가 일관되게 동일한 경우이 접근 방식은 충돌 률이 훨씬 높습니다.

나는 두 세계에서 가장 좋은 알고리즘을 찾고 있습니다 . 해시의 모든 비트를 고려하고 %를 사용하는 것보다 빠릅니다. 반드시 모듈러스 일 필요는 없으며, 범위 0..N-1(N은 버킷의 길이 임) 에 있음을 보장하고 모든 슬롯에 대한 분포를 갖는 것이어야 합니다. 그러한 알고리즘이 존재합니까?

도움 감사합니다.


1
murmurhash3 (smhasher) 의 설명뿐만 아니라 눈사태 효과를 찾아 보십시오 . 그러나 더 나은 해시 함수를 채택하여 질문의 기본 요점을 해결하지 못합니다. 대신, 왜 사용자가 처음에 동일한 더 나은 해시 기능을 채택하지 않는지에 대한 질문이며, 사용자가 악의적으로 게으른 것처럼 대응책을 요구합니다.
rwong


빠른 모듈의 경우 (2^N +/- 1), 참조 stackoverflow.com/questions/763137/...
rwong

@rwong 죄송 합니다만, 귀하의 의견이 내 게시물과 어떤 관련이 있는지 잘 모르겠습니다. 사용자가 제공 한 해시를 제어하지 않으므로 더 나은 해시 기능을 찾고 있지 않습니다. 또한 "악의적으로 게으른 사용자"라는 말의 의미를 이해하지 못합니다.
James Ko

4
해시 함수가 불량한 경우 해시 테이블 구현자가 불량 분포를 "수정"할 수있는 작업이 없습니다. 소수를 모듈로하면 해시가 불량하지 않습니다. 출력, 소수의 배수로 생성되는 해시 함수를 고려하십시오. 실제 프로덕션 코드에서 이러한 문제를 보았습니다.
Frank Hileman

답변:


9

최신 해시 테이블 구현에서는 모듈로 함수를 사용하지 않습니다. 그들은 종종 두 가지 크기의 테이블의 힘을 사용하고 불필요한 비트를 잘라냅니다. 이상적인 해시 함수는 이것을 허용합니다. 소수 자릿수와 결합 된 모듈로의 사용은 종종 .net 개발에서와 같이 해시 함수가 일반적으로 열악한 날에 발생했습니다. 최신 해시 함수 인 SipHash 에 대해 읽은 다음 xxHash 와 같은 다른 최신 함수에 대해 읽어 보는 것이 좋습니다 .

왜 .net 해시 함수가 좋지 않은지 설명해야합니다. .net에서 프로그래머는 종종 GetHashcode를 재정 의하여 해시 함수를 구현해야합니다. 그러나 .net은 프로그래머가 만든 기능을 고품질로 유지하는 데 필요한 도구를 제공하지 않습니다.

  • 구조 또는 클래스에서 해시 상태 캡슐화
  • 해시 상태에 새 데이터를 추가하는 해시 "add"함수 (예 : 바이트 배열 또는 이중 배열 추가)
  • 눈사태를 생성하기위한 해시 "finalize"함수
  • 해시 결과 캡슐화-.net에서는 32 비트 부호있는 정수 중 하나를 선택할 수 있습니다.

해시 함수 결과를 해시 테이블 인덱스로 사용하는 방법에 대한 자세한 내용은이 백서의 범용 해싱 형식에 대한 정의를 참조하십시오. 캐리없는 곱셈을 사용한보다 빠른 64 비트 범용 해싱


3

모든 비트를 계속 유지하면서 AND를 사용하려면 XOR도 사용하십시오.

예를 들어 temp = (hash & 0xFFFF) ^ ( hash >> 16); index = (temp & 0xFF) ^ (temp >> 8);.

이 예제에서는 모듈로가없고 32 비트의 모든 hash8 비트 효과가 index있습니다. 그러나 DIV보다 빠른지 여부는 너무 많은 요소에 따라 달라지며 경우에 따라 DIV보다 느릴 수 있습니다 (예 : 큰 해시 및 작은 인덱스).


이것은 항상 그러나 나는 그것이 내 question--이 응답 생각하지 않는다, 빠른 DIV / IDIV 이상 될 것입니다 index범위에있을 것입니다 [0..255]. 나는 범위에 뭔가가 필요 [0..n-1], n버킷의 수입니다.
James Ko

@JamesKo 그러나 사전을 구현하는 경우 버킷 수를 어느 정도 제어 할 수 있습니다. 따라서 소수 대신 2의 거듭 제곱을 선택할 수 있습니다. (그렇게하는 것이 실제로 좋은 아이디어인지는 말할 수 없습니다.)
svick

@svick 2의 거듭 제곱으로 간단한 마스크 연산을 수행 할 수 있습니다. 질문에서 언급했듯이, 소수 로이 작업을 수행하는 저렴한 방법을 찾고 있으므로 배포가 잘 안된 해시도 수용됩니다.
James Ko

1

많은 소수는 모듈 식 승수를 가지고 있다는 사실을 이용할 수 있습니다. 이 기사를 참조 하십시오 . 버킷 인덱스 소수와 기본적으로 상대적 소수 인 모듈러스 2 ^ n을 만들어 제약 조건 중 하나를 충족했습니다.

이 기사에서는 해당 숫자를 곱하고 오버플로를 무시하면 버킷 인덱스 크기로 나눈 것과 같은 결과를 얻을 수있는 숫자를 찾는 알고리즘에 대해 설명합니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.