回答編集履歴

7

修正

2020/11/15 05:34

投稿

LouiS0616
LouiS0616

スコア35660

test CHANGED
@@ -140,8 +140,28 @@
140
140
 
141
141
 
142
142
 
143
- hash_value = m % P
143
+ hash_value = m
144
144
 
145
145
  return hash_value
146
146
 
147
147
  ```
148
+
149
+
150
+
151
+ hash_value = (abs(m) % P) * pow(n, P - 2, P) % P がちょっと分解しづらいですが、
152
+
153
+ 0. n = 1, 2 < P なので、pow(n, P-2) = 1.
154
+
155
+ hash_value = (abs(m) % P) * (1 % P) % P
156
+
157
+ 0. 0 <= m なので、abs(m) = m.
158
+
159
+ hash_value = (m % P) * (1 % P) % P
160
+
161
+ 0. x < P, xが自然数 なら、x % P = x.
162
+
163
+ hash_value = m * 1 % P
164
+
165
+ hash_value = m % P
166
+
167
+ hash_value = m

6

リンクの修正

2020/11/15 05:34

投稿

LouiS0616
LouiS0616

スコア35660

test CHANGED
@@ -62,6 +62,86 @@
62
62
 
63
63
  **参考**:
64
64
 
65
- - [cpython/setobject.h at master · python/cpython](https://github.com/python/cpython/blob/master/Include/setobject.h)
65
+ - [cpython/setobject.h at master · python/cpython](https://github.com/python/cpython/blob/1a5856bf9295fa73995898d576e0bedf016aee1f/Include/setobject.h)
66
66
 
67
- - [cpython/setobject.c at master · python/cpython](https://github.com/python/cpython/blob/master/Objects/setobject.c)
67
+ - [cpython/setobject.c at master · python/cpython](https://github.com/python/cpython/blob/1a5856bf9295fa73995898d576e0bedf016aee1f/Objects/setobject.c)
68
+
69
+
70
+
71
+ 一年越しの追記
72
+
73
+ ---
74
+
75
+ 64bitマシンのCPythonの場合、`2**61-2`までの自然数nは hash(n) = n と言えそうです。
76
+
77
+ [組み込み型 — Python 3.7.9 ドキュメント](https://docs.python.org/ja/3.7/library/stdtypes.html#hashing-of-numeric-types)
78
+
79
+
80
+
81
+ > ```Python
82
+
83
+ > def hash_fraction(m, n):
84
+
85
+ > """Compute the hash of a rational number m / n.
86
+
87
+
88
+
89
+ > Assumes m and n are integers, with n positive.
90
+
91
+ > Equivalent to hash(fractions.Fraction(m, n)).
92
+
93
+ > """
94
+
95
+ > P = sys.hash_info.modulus
96
+
97
+
98
+
99
+ > # Remove common factors of P. (Unnecessary if m and n already coprime.)
100
+
101
+ > while m % P == n % P == 0:
102
+
103
+ > m, n = m // P, n // P
104
+
105
+
106
+
107
+ > if n % P == 0:
108
+
109
+ > hash_value = sys.hash_info.inf
110
+
111
+ > else:
112
+
113
+ > # Fermat's Little Theorem: pow(n, P-1, P) is 1, so
114
+
115
+ > # pow(n, P-2, P) gives the inverse of n modulo P.
116
+
117
+ > hash_value = (abs(m) % P) * pow(n, P - 2, P) % P
118
+
119
+ > if m < 0:
120
+
121
+ > hash_value = -hash_value
122
+
123
+ > if hash_value == -1:
124
+
125
+ > hash_value = -2
126
+
127
+ > return hash_value
128
+
129
+ > ```
130
+
131
+
132
+
133
+ 0 <= m < P, n = 1 のとき、次のように簡略化できます。
134
+
135
+ ```Python
136
+
137
+ def hash_fraction(m, n):
138
+
139
+ P = sys.hash_info.modulus
140
+
141
+
142
+
143
+ hash_value = m % P
144
+
145
+ return hash_value
146
+
147
+ ```

5

修正

2020/11/15 05:28

投稿

LouiS0616
LouiS0616

スコア35660

test CHANGED
@@ -12,13 +12,13 @@
12
12
 
13
13
  0. セットの内部テーブルの初期サイズは8
14
14
 
15
- 0. 使用済み領域の5倍がテーブルサイズの3倍を超えたとき、テーブルを拡大する処理が入る (**註1**)
15
+ 0. mask領域の5倍がテーブルサイズの3倍以上になったとき、テーブルを拡大する処理が入る (**註1**)
16
16
 
17
17
  0. テーブルはただの配列で、ハッシュ値 mod テーブル長 番目の領域にデータが格納される
18
18
 
19
19
 
20
20
 
21
- n*5 < 8*3 を超える最小の整数nは5です。
21
+ n*5 < 8*3 を満たさない最小の整数nは5です。
22
22
 
23
23
  つまり5要素目を追加するときにテーブルの拡大処理が入っていることになります。
24
24
 
@@ -46,9 +46,9 @@
46
46
 
47
47
  **註1**
48
48
 
49
- 要素を取り除くような処理を行った場合
49
+ mask領域は使用済み(used)領域とダミー領域の和。
50
50
 
51
- ダミー領域がテーブル上に置かれ、これも使用済み領域と見做される
51
+ ダミー領域がテーブル上に置かれるのは要素を取り除くような処理を行った場合
52
52
 
53
53
 
54
54
 

4

追記

2019/11/21 06:07

投稿

LouiS0616
LouiS0616

スコア35660

test CHANGED
@@ -54,7 +54,9 @@
54
54
 
55
55
  **註2**
56
56
 
57
+ 充分小さい自然数nについて、hash(n) = n だったように記憶しています。
58
+
57
- 出典は忘れました。ドキュメントのどっかに書いてあった筈。
59
+ 出典は忘れました。ドキュメントのどっかに書いてあった筈。多分実装依存。
58
60
 
59
61
 
60
62
 

3

修正

2019/11/21 05:41

投稿

LouiS0616
LouiS0616

スコア35660

test CHANGED
@@ -12,7 +12,7 @@
12
12
 
13
13
  0. セットの内部テーブルの初期サイズは8
14
14
 
15
- 0. 使用済み領域の5倍がテーブルサイズの3倍を超えたとき、テーブルを拡大する処理が入る (**註**)
15
+ 0. 使用済み領域の5倍がテーブルサイズの3倍を超えたとき、テーブルを拡大する処理が入る (**註1**)
16
16
 
17
17
  0. テーブルはただの配列で、ハッシュ値 mod テーブル長 番目の領域にデータが格納される
18
18
 
@@ -24,31 +24,37 @@
24
24
 
25
25
 
26
26
 
27
- また、504 mod 8 = 0 ですので、リサイズ前は他の要素より先に置かれるのも納得できます。
27
+ hash(504) mod 8 = 0 ですので(**註2**)、リサイズ前は他の要素より先に置かれるのも納得できます。
28
28
 
29
29
  ```Python
30
30
 
31
31
  >>> {4, 5, 6, 7}
32
32
 
33
- {4, 5, 6, 7} ← n mod 8 の昇順に並ぶ
33
+ {4, 5, 6, 7} ← hash(n) mod 8 の昇順に並ぶ
34
34
 
35
35
  >>> {5, 6, 7, 8}
36
36
 
37
- {8, 5, 6, 7} ← n mod 8 の昇順に並ぶ
37
+ {8, 5, 6, 7} ← hash(n) mod 8 の昇順に並ぶ
38
38
 
39
39
  >>> {5, 6, 7, 8, 9}
40
40
 
41
- {5, 6, 7, 8, 9} ← n mod 16 の昇順に並ぶ
41
+ {5, 6, 7, 8, 9} ← hash(n) mod 16 の昇順に並ぶ
42
42
 
43
43
  ```
44
44
 
45
45
 
46
46
 
47
- **註**
47
+ **註1**
48
48
 
49
49
  要素を取り除くような処理を行った場合、
50
50
 
51
51
  ダミー領域がテーブル上に置かれ、これも使用済み領域と見做される。
52
+
53
+
54
+
55
+ **註2**
56
+
57
+ 出典は忘れました。ドキュメントのどっかに書いてあった筈。
52
58
 
53
59
 
54
60
 

2

追記

2019/11/21 05:40

投稿

LouiS0616
LouiS0616

スコア35660

test CHANGED
@@ -12,7 +12,7 @@
12
12
 
13
13
  0. セットの内部テーブルの初期サイズは8
14
14
 
15
- 0. 使用済み領域の5倍がテーブルサイズの3倍を超えたとき、テーブルを拡大する処理が入る
15
+ 0. 使用済み領域の5倍がテーブルサイズの3倍を超えたとき、テーブルを拡大する処理が入る (**註**)
16
16
 
17
17
  0. テーブルはただの配列で、ハッシュ値 mod テーブル長 番目の領域にデータが格納される
18
18
 
@@ -44,6 +44,14 @@
44
44
 
45
45
 
46
46
 
47
+ **註:**
48
+
49
+ 要素を取り除くような処理を行った場合、
50
+
51
+ ダミー領域がテーブル上に置かれ、これも使用済み領域と見做される。
52
+
53
+
54
+
47
55
  **参考**:
48
56
 
49
57
  - [cpython/setobject.h at master · python/cpython](https://github.com/python/cpython/blob/master/Include/setobject.h)

1

追記

2019/11/21 05:32

投稿

LouiS0616
LouiS0616

スコア35660

test CHANGED
@@ -1 +1,51 @@
1
1
  組み込みの集合は挿入順序を保証しませんので、仕様通りの動作です。
2
+
3
+
4
+
5
+ 追記
6
+
7
+ ---
8
+
9
+ CPythonの実装をざっと読んでみました。
10
+
11
+
12
+
13
+ 0. セットの内部テーブルの初期サイズは8
14
+
15
+ 0. 使用済み領域の5倍がテーブルサイズの3倍を超えたとき、テーブルを拡大する処理が入る
16
+
17
+ 0. テーブルはただの配列で、ハッシュ値 mod テーブル長 番目の領域にデータが格納される
18
+
19
+
20
+
21
+ n*5 < 8*3 を超える最小の整数nは5です。
22
+
23
+ つまり5要素目を追加するときにテーブルの拡大処理が入っていることになります。
24
+
25
+
26
+
27
+ また、504 mod 8 = 0 ですので、リサイズ前は他の要素より先に置かれるのも納得できます。
28
+
29
+ ```Python
30
+
31
+ >>> {4, 5, 6, 7}
32
+
33
+ {4, 5, 6, 7} ← n mod 8 の昇順に並ぶ
34
+
35
+ >>> {5, 6, 7, 8}
36
+
37
+ {8, 5, 6, 7} ← n mod 8 の昇順に並ぶ
38
+
39
+ >>> {5, 6, 7, 8, 9}
40
+
41
+ {5, 6, 7, 8, 9} ← n mod 16 の昇順に並ぶ
42
+
43
+ ```
44
+
45
+
46
+
47
+ **参考**:
48
+
49
+ - [cpython/setobject.h at master · python/cpython](https://github.com/python/cpython/blob/master/Include/setobject.h)
50
+
51
+ - [cpython/setobject.c at master · python/cpython](https://github.com/python/cpython/blob/master/Objects/setobject.c)