author | wenzelm |
Sun, 11 Apr 2010 13:08:14 +0200 | |
changeset 36102 | a51d1d154c71 |
parent 33513 | b2259183e282 |
permissions | -rw-r--r-- |
25728
71e33d95ac55
moved Pure/General/random_word.ML to Tools/random_word.ML;
wenzelm
parents:
diff
changeset
|
1 |
(* Title: Tools/random_word.ML |
71e33d95ac55
moved Pure/General/random_word.ML to Tools/random_word.ML;
wenzelm
parents:
diff
changeset
|
2 |
Author: Makarius |
71e33d95ac55
moved Pure/General/random_word.ML to Tools/random_word.ML;
wenzelm
parents:
diff
changeset
|
3 |
|
71e33d95ac55
moved Pure/General/random_word.ML to Tools/random_word.ML;
wenzelm
parents:
diff
changeset
|
4 |
Simple generator for pseudo-random numbers, using unboxed word |
71e33d95ac55
moved Pure/General/random_word.ML to Tools/random_word.ML;
wenzelm
parents:
diff
changeset
|
5 |
arithmetic only. Unprotected concurrency introduces some true |
71e33d95ac55
moved Pure/General/random_word.ML to Tools/random_word.ML;
wenzelm
parents:
diff
changeset
|
6 |
randomness. |
71e33d95ac55
moved Pure/General/random_word.ML to Tools/random_word.ML;
wenzelm
parents:
diff
changeset
|
7 |
*) |
71e33d95ac55
moved Pure/General/random_word.ML to Tools/random_word.ML;
wenzelm
parents:
diff
changeset
|
8 |
|
71e33d95ac55
moved Pure/General/random_word.ML to Tools/random_word.ML;
wenzelm
parents:
diff
changeset
|
9 |
signature RANDOM_WORD = |
71e33d95ac55
moved Pure/General/random_word.ML to Tools/random_word.ML;
wenzelm
parents:
diff
changeset
|
10 |
sig |
25742 | 11 |
val max_word: word |
12 |
val step: word -> word |
|
13 |
val next_word: unit -> word |
|
14 |
val next_bool: unit -> bool |
|
15 |
val next_int: int -> int -> int |
|
16 |
val next_real: unit -> real |
|
17 |
val pick_any: 'a list -> 'a |
|
18 |
val pick_weighted: (int * 'a) list -> 'a |
|
25728
71e33d95ac55
moved Pure/General/random_word.ML to Tools/random_word.ML;
wenzelm
parents:
diff
changeset
|
19 |
end; |
71e33d95ac55
moved Pure/General/random_word.ML to Tools/random_word.ML;
wenzelm
parents:
diff
changeset
|
20 |
|
33513 | 21 |
structure Random_Word: RANDOM_WORD = |
25728
71e33d95ac55
moved Pure/General/random_word.ML to Tools/random_word.ML;
wenzelm
parents:
diff
changeset
|
22 |
struct |
71e33d95ac55
moved Pure/General/random_word.ML to Tools/random_word.ML;
wenzelm
parents:
diff
changeset
|
23 |
|
25742 | 24 |
(* random words: 0w0 <= result <= max_word *) |
25 |
||
25728
71e33d95ac55
moved Pure/General/random_word.ML to Tools/random_word.ML;
wenzelm
parents:
diff
changeset
|
26 |
(*minimum length of unboxed words on all supported ML platforms*) |
25742 | 27 |
val _ = Word.wordSize >= 30 |
28 |
orelse raise Fail ("Bad platform word size"); |
|
29 |
||
30 |
val max_word = 0wx3FFFFFFF; |
|
31 |
val top_bit = 0wx20000000; |
|
25728
71e33d95ac55
moved Pure/General/random_word.ML to Tools/random_word.ML;
wenzelm
parents:
diff
changeset
|
32 |
|
25742 | 33 |
(*multiplier according to Borosh and Niederreiter (for modulus = 2^30), |
34 |
see http://random.mat.sbg.ac.at/~charly/server/server.html*) |
|
35 |
val a = 0w777138309; |
|
36 |
fun step x = Word.andb (a * x + 0w1, max_word); |
|
37 |
||
32740 | 38 |
local val rand = Unsynchronized.ref 0w1 |
39 |
in fun next_word () = (Unsynchronized.change rand step; ! rand) end; |
|
25742 | 40 |
|
41 |
(*NB: higher bits are more random than lower ones*) |
|
42 |
fun next_bool () = Word.andb (next_word (), top_bit) = 0w0; |
|
43 |
||
44 |
||
45 |
(* random integers: i <= result <= j *) |
|
46 |
||
47 |
val max_int = Word.toInt max_word; |
|
25728
71e33d95ac55
moved Pure/General/random_word.ML to Tools/random_word.ML;
wenzelm
parents:
diff
changeset
|
48 |
|
25742 | 49 |
fun next_int i j = |
50 |
let val k = j - i in |
|
51 |
if k < 0 orelse k > max_int then raise Fail ("next_int: out of range") |
|
52 |
else if k < max_int then i + Word.toInt (Word.mod (next_word (), Word.fromInt (k + 1))) |
|
53 |
else i + Word.toInt (next_word ()) |
|
54 |
end; |
|
55 |
||
56 |
||
57 |
(* random reals: 0.0 <= result < 1.0 *) |
|
58 |
||
59 |
val scaling = real max_int + 1.0; |
|
60 |
fun next_real () = real (Word.toInt (next_word ())) / scaling; |
|
61 |
||
25728
71e33d95ac55
moved Pure/General/random_word.ML to Tools/random_word.ML;
wenzelm
parents:
diff
changeset
|
62 |
|
25742 | 63 |
(* random list elements *) |
64 |
||
65 |
fun pick_any [] = raise Empty |
|
66 |
| pick_any xs = nth xs (next_int 0 (length xs - 1)); |
|
67 |
||
68 |
fun pick_weighted xs = |
|
69 |
let |
|
70 |
val total = fold (fn (k, _) => fn i => |
|
71 |
if k < 0 then raise Fail ("Bad weight: " ^ string_of_int k) else k + i) xs 0; |
|
72 |
fun pick n ((k, x) :: xs) = |
|
73 |
if n <= k then x else pick (n - k) xs |
|
74 |
| pick _ [] = raise Empty; |
|
75 |
in if total = 0 then raise Empty else pick (next_int 1 total) xs end; |
|
25728
71e33d95ac55
moved Pure/General/random_word.ML to Tools/random_word.ML;
wenzelm
parents:
diff
changeset
|
76 |
|
71e33d95ac55
moved Pure/General/random_word.ML to Tools/random_word.ML;
wenzelm
parents:
diff
changeset
|
77 |
end; |
71e33d95ac55
moved Pure/General/random_word.ML to Tools/random_word.ML;
wenzelm
parents:
diff
changeset
|
78 |