-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathalgorithms.fs
103 lines (82 loc) · 2.93 KB
/
algorithms.fs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
(* Algorithms
* By Weisi Dai <[email protected]>
*)
module Weisi.Dai.Algorithms
let AnswerToEverything = 42
// Numeric
let IsOdd x = x % 2 = 1
let Square x = x * x
let IsSquare x =
(x |> float |> sqrt |> int)
|> Square
|> (=) x
let IsPrime x =
seq { 2 .. (x |> float |> sqrt |> int) }
|> Seq.exists (fun divisor -> x % divisor = 0) |> not
let PrimesUpTo n =
let rec sieve sub (current: int[]) =
if current.[sub] > (n |> float |> sqrt |> int)
|| sub > (current.GetUpperBound 0) then current else
current
|> Array.filter (fun x -> (x % current.[sub] <> 0)
|| (x <= current.[sub]))
|> sieve (sub + 1)
sieve 0 [| 2 .. n |]
// Search
type CompareResult =
| COMPARE_HIT = 0
| COMPARE_TOO_SMALL = -1
| COMPARE_TOO_LARGE = 1
let rec BinarySearch low high test =
// ^^ high is unreachable
if (high <= low + 1) && (test low <> CompareResult.COMPARE_HIT) then
None else
let mid = (high + low) / 2
match test mid with
| CompareResult.COMPARE_TOO_LARGE ->
BinarySearch low mid test
| CompareResult.COMPARE_TOO_SMALL ->
BinarySearch mid high test
| CompareResult.COMPARE_HIT | _ -> Some mid
let FindGate low test =
let safeTest x =
if (x < low) then false else
test x
let compareEnter x =
let prev = safeTest (x - 1)
let cur = safeTest x
if not cur then CompareResult.COMPARE_TOO_SMALL else
if prev then CompareResult.COMPARE_TOO_LARGE else
CompareResult.COMPARE_HIT
let rec GateSearch offset step =
if test <| offset + step - 1 then
(BinarySearch offset (offset + step) compareEnter).Value
else
GateSearch (offset + step) (step * 2)
GateSearch low 1
let FindRange low testEnter testLeave =
let lbound = FindGate low testEnter
let ubound = FindGate (lbound - 1) testLeave
(lbound, ubound - 1)
let Compare expected actual =
if actual < expected then CompareResult.COMPARE_TOO_SMALL else
if actual > expected then CompareResult.COMPARE_TOO_LARGE else
CompareResult.COMPARE_HIT
// Combinatorics
let NextPermutation (current: 'a []) =
let rec findRev pos =
if pos = 0 then None else
if current.[pos - 1] < current.[pos] then Some pos else
findRev (pos - 1)
let last = current.GetUpperBound 0
match findRev last with
| None -> None
| Some pos -> let lowest = current.[pos .. last]
|> Array.filter ((<) current.[pos - 1])
|> Seq.ofArray |> Seq.min
current.[pos - 1 .. last]
|> Array.filter ((<>) lowest)
|> Array.sort
|> Array.append [| lowest |]
|> Array.append current.[0 .. pos - 2]
|> Some