Skip to content
This repository was archived by the owner on May 22, 2026. It is now read-only.

Commit 6e189f9

Browse files
feat: etatostenes turner
1 parent 8772e3b commit 6e189f9

4 files changed

Lines changed: 99 additions & 23 deletions

File tree

math/eratosthenes/eratosthenes.hs

Lines changed: 0 additions & 17 deletions
This file was deleted.

math/prime_number/README.md

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
# 素数関連のアルゴリズム
2+
3+
## エラトステネスの篩
4+
5+
- 見つけた素数の倍数を消していく方法。
6+
- 事前に素数かどうかを記録する配列を用意しておく。
7+
- i=2の時にはn/2回の更新が、i=3の時にはn/3回の更新が行われるため、全体の更新回数はn/2 + n/3 + n/5 + ... = n(1/2 + 1/3 + 1/5 + ...) = O(n log log n)となる。
8+
9+
### 計算量の見積もりの考え方
10+
11+
素数定理より
12+
π(n) ≈ n / log n
13+
であるため、素数の個数はn/log n程度であることがわかる。
14+
そのため、確率で重み付けを行うことで、素数の逆数の和は、
15+
16+
$$\sum_{k=1}^{n} \frac{1}{k} \cdot \frac{1}{\log k}$$
17+
に近似される。
18+
19+
これを積分近似する。
20+
21+
$$
22+
\int_{2}^{n} \frac{dx}{x \log x}
23+
$$
24+
25+
$t = \log x$を使い、置換積分を行う。
26+
27+
$$
28+
dt = \frac{dx}{x}
29+
$$
30+
31+
$$
32+
\int \frac{dx}{x \log x}
33+
= \int \frac{dt}{t}
34+
= \log t
35+
$$
36+
37+
置換を戻して
38+
39+
$$
40+
\log (\log n)
41+
$$
42+
43+
よって、素数の逆数の和はO(log log n)であることがわかる。
44+
45+
### 実装例
46+
47+
- [ ] Python
48+
- [ ] C
49+
- [x] Haskell
50+
51+
---
52+
53+
## Turnerの篩
54+
55+
1. 2からnまでの数をリストに入れる。
56+
2. リストの先頭はpを取り出す。pは必ず素数である(2が素数であり、3の処理の結果p以下の素数すべてで割ったあまりが0にならない数がリストに残るため)。pを素数リストに追加する。
57+
3. pで割ったあまりが0になる数をリストから削除して2に戻る。
58+
59+
洗練された見た目だが、エラトステネスの篩に比べて実際はO(n^2/(log n)^2)
60+
61+
### 実装例
62+
63+
- [ ] Python
64+
- [ ] C
65+
- [x] Haskell
Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,37 +2,45 @@ import Control.Monad (forM_, when)
22
import Data.Vector.Unboxed qualified as VU
33
import Data.Vector.Unboxed.Mutable qualified as VUM
44

5-
type PrimeTable = VU.Vector Bool
5+
type PrimeTable = VU.Vector Bool -- i番目の数字が素数かどうかをBoolで管理するtable
66

7+
-- 素数のリストを返す
78
primeTableToList :: PrimeTable -> [Int]
89
primeTableToList t =
910
[ i
1011
| i <- [0 .. VU.length t - 1],
1112
t VU.! i
1213
]
1314

15+
-- PrimeTableに入っていれば素数であると判定する。
1416
isInPrimeTable :: PrimeTable -> Int -> Bool
1517
isInPrimeTable t n
1618
| 0 <= n && n < VU.length t = t VU.! n
1719
| otherwise = error "out of range"
1820

21+
-- 先頭の値iはかならす素数なので、iの倍数を生成して素数でないものを弾いていく。
1922
sieve :: Int -> PrimeTable
2023
sieve n = VU.create $ do
2124
vec <- VUM.replicate (n + 1) True
25+
-- 0、1は素数でない
2226
VUM.write vec 0 False
2327
VUM.write vec 1 False
2428
forM_ [2 .. n] $ \i -> do
2529
b <- VUM.read vec i
2630
when b $ do
2731
forM_ [2 * i, 3 * i .. n] $ \j -> do
32+
-- ghci> [2 * i , 3 * i ..10]=[4,6,8,10]
2833
VUM.write vec j False
2934
return vec
3035

36+
main :: IO ()
3137
main = do
38+
-- 100までの素数を作る
3239
let t = sieve 100
33-
print $ primeTableToList t
40+
print t
41+
let prime = primeTableToList t
42+
print prime
3443

35-
-- print $ take 20 primes
36-
-- print $ 7 `elem` primes
37-
38-
-- print $ 102 `elem` primes -- 素数でない数を探索すると止まらない
44+
-- 素数判定
45+
print $ isInPrimeTable t 47
46+
print $ isInPrimeTable t 57

math/prime_number/turner.hs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
-- これはTurnerのふるいであってエラトステネスのふるいではないらしい
2+
primes :: [Int]
3+
primes = 2 : sieve [3, 5 ..] -- 2+奇数の無限配列
4+
where
5+
-- 初期値2は素数であり、pはそれより小さい素数の合成数でないため、リストの先頭は必ず素数である
6+
-- pで割ったあまりが0になる数をリストから削除することを繰り返すことで素数のリストができる。
7+
sieve (p : xs) =
8+
p
9+
: sieve
10+
[ x
11+
| x <- xs,
12+
x `mod` p /= 0
13+
]
14+
15+
main :: IO ()
16+
main = do
17+
print $ take 20 primes
18+
print $ 7 `elem` primes
19+
20+
-- print $ 102 `elem` primes -- 素数でない数を探索すると止まらない

0 commit comments

Comments
 (0)