| author | wenzelm | 
| Fri, 20 Nov 2009 15:33:10 +0100 | |
| changeset 33820 | 082d9bc6992d | 
| 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 |