Commit | Line | Data |
---|---|---|
7f918cf1 CE |
1 | (* Copyright (C) 2009,2017 Matthew Fluet. |
2 | * Copyright (C) 1999-2006 Henry Cejtin, Matthew Fluet, Suresh | |
3 | * Jagannathan, and Stephen Weeks. | |
4 | * | |
5 | * MLton is released under a BSD-style license. | |
6 | * See the file MLton-LICENSE for details. | |
7 | *) | |
8 | ||
9 | structure Random: RANDOM = | |
10 | struct | |
11 | ||
12 | local | |
13 | open MLton.Random | |
14 | in | |
15 | val alphaNumString = alphaNumString | |
16 | val seed = seed | |
17 | val useed = useed | |
18 | val word = rand | |
19 | val srand = srand | |
20 | end | |
21 | ||
22 | val word = Trace.trace ("Random.word", Unit.layout, Word.layout) word | |
23 | val srand = Trace.trace ("Random.srand", Word.layout, Unit.layout) srand | |
24 | ||
25 | local | |
26 | val ri: int ref = ref 0 | |
27 | val rw = ref (word ()) | |
28 | val max = Word.wordSize - 1 | |
29 | in | |
30 | fun bool () = | |
31 | let | |
32 | val i = !ri | |
33 | val b = 0w1 = Word.andb (0wx1, Word.>> (!rw, Word.fromInt i)) | |
34 | val _ = | |
35 | if i = max | |
36 | then (rw := word () | |
37 | ; ri := 0) | |
38 | else ri := 1 + i | |
39 | in b | |
40 | end | |
41 | end | |
42 | ||
43 | fun int () = Word.toIntX (word ()) | |
44 | ||
45 | val int = Trace.trace ("Random.int", Unit.layout, Int.layout) int | |
46 | ||
47 | local | |
48 | val maxNat = | |
49 | let | |
50 | val shft = Option.fold (Int.precision, Word.wordSize, Int.min) | |
51 | val shft = Word.fromInt (shft - 1) | |
52 | in | |
53 | Word.toInt (Word.notb (Word.<< (Word.notb 0w0, shft))) | |
54 | end | |
55 | ||
56 | val maxNatW = Word.fromInt maxNat | |
57 | ||
58 | fun nat () = Word.toInt (Word.andb (word (), maxNatW)) | |
59 | ||
60 | val nat = Trace.trace ("Random.nat", Unit.layout, Int.layout) nat | |
61 | ||
62 | val maxNatR = Real.fromInt maxNat | |
63 | ||
64 | fun scale r = r / maxNatR | |
65 | ||
66 | val natReal = Real.fromInt o nat | |
67 | ||
68 | val natReal = Trace.trace0 ("Random.natReal", Real.layout) natReal | |
69 | in | |
70 | fun real () = scale (natReal () + scale (natReal ())) | |
71 | ||
72 | val real = Trace.trace0 ("Random.real", Real.layout) real | |
73 | end | |
74 | ||
75 | local | |
76 | val r: word ref = ref 0w0 | |
77 | val max: word ref = ref 0w0 | |
78 | in | |
79 | fun wordLessThan (w: word): word = | |
80 | if w = 0w0 | |
81 | then Error.bug "Random.wordLessThan" | |
82 | else | |
83 | let | |
84 | val () = | |
85 | if w - 0w1 <= !max | |
86 | then () | |
87 | else (r := word () | |
88 | ; max := Word.notb 0wx0) | |
89 | val w' = !r | |
90 | val () = r := Word.div (w', w) | |
91 | val () = max := Word.div (!max, w) | |
92 | in | |
93 | Word.mod (w', w) | |
94 | end | |
95 | end | |
96 | ||
97 | fun natLessThan (n: int): int = | |
98 | if n <= 0 | |
99 | then Error.bug "Random.natLessThan" | |
100 | else Word.toInt (wordLessThan (Word.fromInt n)) | |
101 | ||
102 | fun charFrom (s: string): char = | |
103 | Pervasive.String.sub (s, natLessThan (Pervasive.String.size s)) | |
104 | ||
105 | fun nRandom {list, length, n} = | |
106 | let | |
107 | fun loop (need: int, length: int, xs: 'a list, ac: 'a list): 'a list = | |
108 | (Assert.assert ("Random.nRandom", fn () => need <= length) | |
109 | ; if need <= 0 | |
110 | then ac | |
111 | else (case xs of | |
112 | [] => Error.bug "nRandom" | |
113 | | x :: xs => | |
114 | if natLessThan length < need | |
115 | then loop (need - 1, length - 1, xs, x :: ac) | |
116 | else loop (need, length - 1, xs, ac))) | |
117 | in loop (n, length, list, []) | |
118 | end | |
119 | ||
120 | val nRandom = fn x => | |
121 | Assert.assertFun | |
122 | ("nRandom", nRandom, | |
123 | fn {list, length, n} => (length = List.length list | |
124 | andalso 0 <= n | |
125 | andalso n <= length, | |
126 | fn l => n = List.length l)) | |
127 | x | |
128 | ||
129 | fun list l = | |
130 | let | |
131 | val n = List.length l | |
132 | in | |
133 | if n = 0 | |
134 | then NONE | |
135 | else SOME (List.nth (l, natLessThan n)) | |
136 | end | |
137 | ||
138 | end |