Import Upstream version 20180207
[hcoop/debian/mlton.git] / lib / mlton / basic / random.sml
CommitLineData
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
9structure Random: RANDOM =
10struct
11
12local
13 open MLton.Random
14in
15 val alphaNumString = alphaNumString
16 val seed = seed
17 val useed = useed
18 val word = rand
19 val srand = srand
20end
21
22val word = Trace.trace ("Random.word", Unit.layout, Word.layout) word
23val srand = Trace.trace ("Random.srand", Word.layout, Unit.layout) srand
24
25local
26 val ri: int ref = ref 0
27 val rw = ref (word ())
28 val max = Word.wordSize - 1
29in
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
41end
42
43fun int () = Word.toIntX (word ())
44
45val int = Trace.trace ("Random.int", Unit.layout, Int.layout) int
46
47local
48val 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
56val maxNatW = Word.fromInt maxNat
57
58fun nat () = Word.toInt (Word.andb (word (), maxNatW))
59
60val nat = Trace.trace ("Random.nat", Unit.layout, Int.layout) nat
61
62val maxNatR = Real.fromInt maxNat
63
64fun scale r = r / maxNatR
65
66val natReal = Real.fromInt o nat
67
68val natReal = Trace.trace0 ("Random.natReal", Real.layout) natReal
69in
70fun real () = scale (natReal () + scale (natReal ()))
71
72val real = Trace.trace0 ("Random.real", Real.layout) real
73end
74
75local
76 val r: word ref = ref 0w0
77 val max: word ref = ref 0w0
78in
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
95end
96
97fun natLessThan (n: int): int =
98 if n <= 0
99 then Error.bug "Random.natLessThan"
100 else Word.toInt (wordLessThan (Word.fromInt n))
101
102fun charFrom (s: string): char =
103 Pervasive.String.sub (s, natLessThan (Pervasive.String.size s))
104
105fun 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
120val 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
129fun 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
138end