문제

당 Java 설명서 hash codeString 체로 계산:

s[0]*31^(n-1) + s[1]*31^(n-2) + ... + s[n-1]

int 산,가 s[i]번째 문자의 문자열 n 의 길이 문자열 ^ 음을 나타냅 지수.

왜 31 으로 사용 multiplier?

내가 이해하는 배수해야 상대적으로 많은 소수가 아니다.왜 29,또는 37,또는 97?

도움이 되었습니까?

해결책

Joshua Bloch 's에 따르면 효과적인 자바 (충분히 추천 할 수없고 StackoverFlow에 대한 지속적인 언급 덕분에 구입 한 책) :

값 31은 홀수 프라임이기 때문에 선택되었습니다. 균일 한 곱셈이 넘치면 2의 곱셈이 이동과 동일하기 때문에 정보가 손실됩니다. 프라임을 사용하는 이점은 명확하지 않지만 전통적입니다. 31의 멋진 속성은 곱셈이 더 나은 성능을위한 교대와 뺄셈으로 대체 될 수 있다는 것입니다. 31 * i == (i << 5) - i. 최신 VM은 이러한 종류의 최적화를 자동으로 수행합니다.

(3 장, 항목 9 : 항상 해시 코드를 재정의 할 때, 48 페이지를 재정의 할 때)

다른 팁

처럼 굿 리치와 타마 시아 지적하면, 50,000 개 이상의 영어 단어 (UNIX의 두 가지 변형으로 제공되는 단어 목록의 결합으로 형성됨)를 사용하면 상수 31, 33, 37, 39 및 41을 사용하여 각 경우에 7 개 미만의 충돌이 발생합니다. 이를 알면 많은 Java 구현이 이러한 상수 중 하나를 선택한다는 것은 놀라운 일이 아닙니다.

우연히도, 나는이 질문을 보았을 때 "다항식 해시 코드"섹션을 읽는 중에있었습니다.

편집 : 여기에 언급하고있는 ~ 10MB PDF 책에 대한 링크는 다음과 같습니다. 섹션 10.2 해시 테이블 (413 페이지)을 참조하십시오. Java의 데이터 구조 및 알고리즘

(대부분) 오래된 프로세서에서 31을 곱하면 상대적으로 저렴할 수 있습니다. 예를 들어 팔에 하나의 지침 일뿐입니다.

RSB       r1, r0, r0, ASL #5    ; r1 := - r0 + (r0<<5)

대부분의 다른 프로세서에는 별도의 교대 및 빼기 명령이 필요합니다. 그러나 승수가 느리면 여전히 승리입니다. 현대 프로세서는 빠른 승수를 갖는 경향이 있으므로 32가 올바른면에서 진행되는 한 크게 차이가 없습니다.

훌륭한 해시 알고리즘은 아니지만 1.0 코드보다 충분하고 좋습니다 (1.0 사양보다 훨씬 좋습니다).

곱하면 비트가 왼쪽으로 이동합니다. 이는 사용 가능한 해시 코드의 더 많은 공간을 사용하여 충돌을 줄입니다.

2의 전력을 사용하지 않음으로써 하위 주문, 오른쪽 비트도 채워져 다음 데이터의 데이터가 해시로 들어가는 것과 혼합됩니다.

표현식 n * 31 동일합니다 (n << 5) - n.

"의견"에서 Bloch의 원래 추론을 읽을 수 있습니다. http://bugs.java.com/bugdatabase/view_bug.do?bug_id=4045622. 그는 해시 테이블에서 결과 "평균 체인 크기"와 관련하여 다른 해시 기능의 성능을 조사했습니다. P(31) 그 당시 그가 K & R의 책에서 찾은 일반적인 기능 중 하나였습니다 (그러나 Kernighan과 Ritchie조차도 어디에서 왔는지 기억할 수 없었습니다). 결국 그는 기본적으로 하나를 선택해야했고 그는 P(31) 충분히 성능이 좋았 기 때문입니다. 일지라도 P(33) 실제로는 더 나쁘지 않았고 33의 곱셈은 똑같이 빠르며 (5만큼의 변화와 추가), 그는 33이 프라임이 아니기 때문에 31을 선택했습니다.

나머지 4 개 중에서, 나는 아마도 P (31)를 선택할 것입니다. RISC 기계에서 가장 저렴하기 때문에 (31은 2 개의 전력의 차이이기 때문에) 아마도 P (31)를 선택합니다. P (33)은 계산하기가 비슷하지만 성능은 약간 악화되고 33은 복합재이므로 약간 긴장합니다.

따라서 여기의 많은 답변이 암시하는 것처럼 추론은 합리적이지 않았습니다. 그러나 우리는 장의 결정 후 합리적인 이유를 제시하는 데 능숙합니다 (그리고 Bloch조차도 그 일이 발생하기 쉬운 것일 수도 있습니다).

사실, 37은 꽤 잘 작동합니다! Z : = 37 * x는 다음과 같이 계산할 수 있습니다. y := x + 8 * x; z := x + 4 * y. 두 단계 모두 하나의 LEA X86 지침에 해당하므로 매우 빠릅니다.

실제로, 균일 한 프라임과의 곱셈 73 설정하여 같은 속도로 수행 할 수 있습니다 y := x + 8 * x; z := x + 8 * y.

73 또는 37 (31 대신)을 사용하면 더 나을 수 있습니다. 밀도가 높은 코드: 2 개의 LEA 지침은 6 바이트와 Move+Shift+SUPTOR의 7 바이트 만 31까지 곱하기를 위해 6 바이트 만 가져옵니다. 여기에 사용 된 3- 경사 LEA 지침은 Intel의 Sandy Bridge Architecture에서 느리게되었다는 것입니다. 3 사이클의 대기 시간.

더구나, 73 Sheldon Cooper가 가장 좋아하는 번호입니다.

닐 코피 설명합니다 왜 31이 사용되는지 편견을 다림질합니다.

기본적으로 31을 사용하면 해시 함수에 대한 더 짝수 설정 비트 확률 분포가 제공됩니다.

JDK-4045622, 곳 여호수아는 블로흐에 대해 설명합하는 이유는 특별한(new) String.hashCode() 구현이 선택

테이블 아래 요약의 성능을 다양한 해쉬 기능 설명하는 위의 세 가지 데이터 세트:

1)모든 단어 및 어구 항목에서 Merriam-Webster's 2nd Int'l 무삭제전(311,141 문자열 avg 길이 10chars).

2)문자열의 모든에서는/bin/,/usr/bin/,/usr/lib/,/usr/ucb/ 고/usr/openwin/bin/*(66,304 문자열 avg 길이 21 자).

3)목록의 Url 을 수집한 웹 크롤러는 여러 가지 실행 시간 마지막 밤(28,372 문자열 avg 길이 49 자).

성능 메트릭을 다음과 같이 테이블에이의"체인 평균 크기" 모든 요소에서 해시 테이블(즉,예상의 가치 의 숫자 키를 비교하는 요소)

                          Webster's   Code Strings    URLs
                          ---------   ------------    ----
Current Java Fn.          1.2509      1.2738          13.2560
P(37)    [Java]           1.2508      1.2481          1.2454
P(65599) [Aho et al]      1.2490      1.2510          1.2450
P(31)    [K+R]            1.2500      1.2488          1.2425
P(33)    [Torek]          1.2500      1.2500          1.2453
Vo's Fn                   1.2487      1.2471          1.2462
WAIS Fn                   1.2497      1.2519          1.2452
Weinberger's Fn(MatPak)   6.5169      7.2142          30.6864
Weinberger's Fn(24)       1.3222      1.2791          1.9732
Weinberger's Fn(28)       1.2530      1.2506          1.2439

이 테이블의 명확한 그의 모든 기능을 제외한 현재는 Java 기능과 두 깨진 버전의 Weinberger 의 는 기능을 제공한,거의 구별할 수 없는 성능이다.나 강력하게 추측하는 이는 성능 기본적으로 "이론적 이상적인",당신이 무엇을 얻을 거라고 사용하는 경우 true random 번호 생성기에서의 해쉬 기능입니다.

난제의 웨이스 디바이드 기능으로 그 사양이 포함되어 페이지를 임의의 숫자,그리고 그 성능이 더 나은 어떤 것보다 훨씬 간단 기능이 있다.의 나머지는 여섯 기능처럼 보일 훌륭한 선택,그러나 우리는할 수 있는 기회를 제공합니다.나는 가정 난제 Vo 의 변형 및 Weinberger 의 기능 때문에 추가 복잡도,이기는 하지만 작습니다.의 나머지 네 가지,나는 아마 선택 P(31),그것의 가장 저렴한 계산에 RISC machine(기 때문 31 의 차이는 두 권의 두).P(33)마찬가지로 저렴 계산지만,그것의 성능은 소폭이 악화하고,33 복합하는 나에게 긴장되어 있습니다.

Josh

확실하지 않지만 소수 샘플을 테스트했으며 31이 가능한 일부 샘플보다 최상의 분포를 주었다는 것을 알았습니다.

Bloch는 이것에 들어 가지 않지만, 내가 항상 들었거나 믿었던 이론적 근거는 이것이 기본 대수라는 것입니다. 해시는 곱셈 및 모듈러스 작업으로 요약되므로 도움을 줄 수있는 경우 공통 요소가있는 숫자를 사용하고 싶지 않습니다. 다시 말해, 상대적으로 소수는 짝수의 답변을 제공합니다.

해시를 사용하는 숫자는 일반적으로 다음과 같습니다.

  • 데이터 유형의 계수 (2^32 또는 2^64)
  • 해시 가능에있는 버킷 카운트의 계수 (변동. 자바에서는 프라임이었고, 이제 2^n)
  • 믹싱 기능에서 마법 번호를 곱하거나 이동
  • 입력 값

당신은 실제로이 값들 중 몇 가지만 제어 할 수 있으므로 약간의 추가 치료가 필요합니다.

최신 버전의 JDK에서는 31이 여전히 사용됩니다. https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/lang/string.html#hashcode ()

해시 문자열의 목적은입니다

  • 고유 한 (운영자를 참조하십시오 ^ 해시 코드 계산 문서에서 고유 한 도움이됩니다)
  • 계산 비용 저렴한 비용

31은 최대 값이 8 비트 (= 1 바이트) 레지스터를 넣을 수 있습니다. 가장 큰 소수는 1 바이트 레지스터에 넣을 수 있으며 홀수입니다.

곱하기 31은 << 5입니다. 그러면 저렴한 자원이 필요합니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top