teratail header banner
teratail header banner
質問するログイン新規登録

回答編集履歴

7

修正

2020/11/15 05:34

投稿

LouiS0616
LouiS0616

スコア35678

answer CHANGED
@@ -69,6 +69,16 @@
69
69
  def hash_fraction(m, n):
70
70
  P = sys.hash_info.modulus
71
71
 
72
- hash_value = m % P
72
+ hash_value = m
73
73
  return hash_value
74
- ```
74
+ ```
75
+
76
+ hash_value = (abs(m) % P) * pow(n, P - 2, P) % P がちょっと分解しづらいですが、
77
+ 0. n = 1, 2 < P なので、pow(n, P-2) = 1.
78
+ hash_value = (abs(m) % P) * (1 % P) % P
79
+ 0. 0 <= m なので、abs(m) = m.
80
+ hash_value = (m % P) * (1 % P) % P
81
+ 0. x < P, xが自然数 なら、x % P = x.
82
+ hash_value = m * 1 % P
83
+ hash_value = m % P
84
+ hash_value = m

6

リンクの修正

2020/11/15 05:34

投稿

LouiS0616
LouiS0616

スコア35678

answer CHANGED
@@ -30,5 +30,45 @@
30
30
  出典は忘れました。ドキュメントのどっかに書いてあった筈。多分実装依存。
31
31
 
32
32
  **参考**:
33
- - [cpython/setobject.h at master · python/cpython](https://github.com/python/cpython/blob/master/Include/setobject.h)
33
+ - [cpython/setobject.h at master · python/cpython](https://github.com/python/cpython/blob/1a5856bf9295fa73995898d576e0bedf016aee1f/Include/setobject.h)
34
- - [cpython/setobject.c at master · python/cpython](https://github.com/python/cpython/blob/master/Objects/setobject.c)
34
+ - [cpython/setobject.c at master · python/cpython](https://github.com/python/cpython/blob/1a5856bf9295fa73995898d576e0bedf016aee1f/Objects/setobject.c)
35
+
36
+ 一年越しの追記
37
+ ---
38
+ 64bitマシンのCPythonの場合、`2**61-2`までの自然数nは hash(n) = n と言えそうです。
39
+ [組み込み型 — Python 3.7.9 ドキュメント](https://docs.python.org/ja/3.7/library/stdtypes.html#hashing-of-numeric-types)
40
+
41
+ > ```Python
42
+ > def hash_fraction(m, n):
43
+ > """Compute the hash of a rational number m / n.
44
+
45
+ > Assumes m and n are integers, with n positive.
46
+ > Equivalent to hash(fractions.Fraction(m, n)).
47
+ > """
48
+ > P = sys.hash_info.modulus
49
+
50
+ > # Remove common factors of P. (Unnecessary if m and n already coprime.)
51
+ > while m % P == n % P == 0:
52
+ > m, n = m // P, n // P
53
+
54
+ > if n % P == 0:
55
+ > hash_value = sys.hash_info.inf
56
+ > else:
57
+ > # Fermat's Little Theorem: pow(n, P-1, P) is 1, so
58
+ > # pow(n, P-2, P) gives the inverse of n modulo P.
59
+ > hash_value = (abs(m) % P) * pow(n, P - 2, P) % P
60
+ > if m < 0:
61
+ > hash_value = -hash_value
62
+ > if hash_value == -1:
63
+ > hash_value = -2
64
+ > return hash_value
65
+ > ```
66
+
67
+ 0 <= m < P, n = 1 のとき、次のように簡略化できます。
68
+ ```Python
69
+ def hash_fraction(m, n):
70
+ P = sys.hash_info.modulus
71
+
72
+ hash_value = m % P
73
+ return hash_value
74
+ ```

5

修正

2020/11/15 05:28

投稿

LouiS0616
LouiS0616

スコア35678

answer CHANGED
@@ -5,10 +5,10 @@
5
5
  CPythonの実装をざっと読んでみました。
6
6
 
7
7
  0. セットの内部テーブルの初期サイズは8
8
- 0. 使用済み領域の5倍がテーブルサイズの3倍を超えたとき、テーブルを拡大する処理が入る (**註1**)
8
+ 0. mask領域の5倍がテーブルサイズの3倍以上になったとき、テーブルを拡大する処理が入る (**註1**)
9
9
  0. テーブルはただの配列で、ハッシュ値 mod テーブル長 番目の領域にデータが格納される
10
10
 
11
- n*5 < 8*3 を超える最小の整数nは5です。
11
+ n*5 < 8*3 を満たさない最小の整数nは5です。
12
12
  つまり5要素目を追加するときにテーブルの拡大処理が入っていることになります。
13
13
 
14
14
  hash(504) mod 8 = 0 ですので(**註2**)、リサイズ前は他の要素より先に置かれるのも納得できます。
@@ -22,8 +22,8 @@
22
22
  ```
23
23
 
24
24
  **註1**
25
- 要素を取り除くような処理を行った場合
25
+ mask領域は使用済み(used)領域とダミー領域の和。
26
- ダミー領域がテーブル上に置かれ、これも使用済み領域と見做される。
26
+ ダミー領域がテーブル上に置かれるのは、要素を取り除くような処理を行った場合
27
27
 
28
28
  **註2**
29
29
  充分小さい自然数nについて、hash(n) = n だったように記憶しています。

4

追記

2019/11/21 06:07

投稿

LouiS0616
LouiS0616

スコア35678

answer CHANGED
@@ -26,7 +26,8 @@
26
26
  ダミー領域がテーブル上に置かれ、これも使用済み領域と見做される。
27
27
 
28
28
  **註2**
29
+ 充分小さい自然数nについて、hash(n) = n だったように記憶しています。
29
- 出典は忘れました。ドキュメントのどっかに書いてあった筈。
30
+ 出典は忘れました。ドキュメントのどっかに書いてあった筈。多分実装依存。
30
31
 
31
32
  **参考**:
32
33
  - [cpython/setobject.h at master · python/cpython](https://github.com/python/cpython/blob/master/Include/setobject.h)

3

修正

2019/11/21 05:41

投稿

LouiS0616
LouiS0616

スコア35678

answer CHANGED
@@ -5,26 +5,29 @@
5
5
  CPythonの実装をざっと読んでみました。
6
6
 
7
7
  0. セットの内部テーブルの初期サイズは8
8
- 0. 使用済み領域の5倍がテーブルサイズの3倍を超えたとき、テーブルを拡大する処理が入る (**註**)
8
+ 0. 使用済み領域の5倍がテーブルサイズの3倍を超えたとき、テーブルを拡大する処理が入る (**註1**)
9
9
  0. テーブルはただの配列で、ハッシュ値 mod テーブル長 番目の領域にデータが格納される
10
10
 
11
11
  n*5 < 8*3 を超える最小の整数nは5です。
12
12
  つまり5要素目を追加するときにテーブルの拡大処理が入っていることになります。
13
13
 
14
- また、504 mod 8 = 0 ですので、リサイズ前は他の要素より先に置かれるのも納得できます。
14
+ hash(504) mod 8 = 0 ですので(**註2**)、リサイズ前は他の要素より先に置かれるのも納得できます。
15
15
  ```Python
16
16
  >>> {4, 5, 6, 7}
17
- {4, 5, 6, 7} ← n mod 8 の昇順に並ぶ
17
+ {4, 5, 6, 7} ← hash(n) mod 8 の昇順に並ぶ
18
18
  >>> {5, 6, 7, 8}
19
- {8, 5, 6, 7} ← n mod 8 の昇順に並ぶ
19
+ {8, 5, 6, 7} ← hash(n) mod 8 の昇順に並ぶ
20
20
  >>> {5, 6, 7, 8, 9}
21
- {5, 6, 7, 8, 9} ← n mod 16 の昇順に並ぶ
21
+ {5, 6, 7, 8, 9} ← hash(n) mod 16 の昇順に並ぶ
22
22
  ```
23
23
 
24
- **註**
24
+ **註1**
25
25
  要素を取り除くような処理を行った場合、
26
26
  ダミー領域がテーブル上に置かれ、これも使用済み領域と見做される。
27
27
 
28
+ **註2**
29
+ 出典は忘れました。ドキュメントのどっかに書いてあった筈。
30
+
28
31
  **参考**:
29
32
  - [cpython/setobject.h at master · python/cpython](https://github.com/python/cpython/blob/master/Include/setobject.h)
30
33
  - [cpython/setobject.c at master · python/cpython](https://github.com/python/cpython/blob/master/Objects/setobject.c)

2

追記

2019/11/21 05:40

投稿

LouiS0616
LouiS0616

スコア35678

answer CHANGED
@@ -5,7 +5,7 @@
5
5
  CPythonの実装をざっと読んでみました。
6
6
 
7
7
  0. セットの内部テーブルの初期サイズは8
8
- 0. 使用済み領域の5倍がテーブルサイズの3倍を超えたとき、テーブルを拡大する処理が入る
8
+ 0. 使用済み領域の5倍がテーブルサイズの3倍を超えたとき、テーブルを拡大する処理が入る (**註**)
9
9
  0. テーブルはただの配列で、ハッシュ値 mod テーブル長 番目の領域にデータが格納される
10
10
 
11
11
  n*5 < 8*3 を超える最小の整数nは5です。
@@ -21,6 +21,10 @@
21
21
  {5, 6, 7, 8, 9} ← n mod 16 の昇順に並ぶ
22
22
  ```
23
23
 
24
+ **註:**
25
+ 要素を取り除くような処理を行った場合、
26
+ ダミー領域がテーブル上に置かれ、これも使用済み領域と見做される。
27
+
24
28
  **参考**:
25
29
  - [cpython/setobject.h at master · python/cpython](https://github.com/python/cpython/blob/master/Include/setobject.h)
26
30
  - [cpython/setobject.c at master · python/cpython](https://github.com/python/cpython/blob/master/Objects/setobject.c)

1

追記

2019/11/21 05:32

投稿

LouiS0616
LouiS0616

スコア35678

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