[MLton] cvs commit: rewrite of MLton.Random.alphaNumString

Stephen Weeks sweeks@mlton.org
Sun, 28 Dec 2003 15:15:01 -0800


sweeks      03/12/28 15:15:01

  Modified:    basis-library/mlton random.sig random.sml
               lib/mlton-stubs random.sml
  Log:
  MAIL rewrite of MLton.Random.alphaNumString
  
  Used Matthew's (excellent) suggestion to compute the refresh period.
  Also added alphaNumChar, which will save even a few more random bits.
  
  Please check for errors :-).

Revision  Changes    Path
1.4       +3 -0      mlton/basis-library/mlton/random.sig

Index: random.sig
===================================================================
RCS file: /cvsroot/mlton/mlton/basis-library/mlton/random.sig,v
retrieving revision 1.3
retrieving revision 1.4
diff -u -r1.3 -r1.4
--- random.sig	10 Apr 2003 02:03:01 -0000	1.3
+++ random.sig	28 Dec 2003 23:15:00 -0000	1.4
@@ -3,6 +3,9 @@
    
 signature MLTON_RANDOM =
    sig
+      (* Return a random alphanumeric character. *)
+      val alphaNumChar: unit -> char
+	 
       (* Return a string of random alphanumeric characters of specified
        * length.
        *)



1.8       +21 -16    mlton/basis-library/mlton/random.sml

Index: random.sml
===================================================================
RCS file: /cvsroot/mlton/mlton/basis-library/mlton/random.sml,v
retrieving revision 1.7
retrieving revision 1.8
diff -u -r1.7 -r1.8
--- random.sml	28 Dec 2003 22:43:48 -0000	1.7
+++ random.sml	28 Dec 2003 23:15:00 -0000	1.8
@@ -61,22 +61,27 @@
       local
 	 val chars =
 	    "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
-	 val n = Word.fromInt (String.size chars)
-	 val r: word ref = ref 0w0
+	 val refresh =
+	    Int.quot (Word.wordSize,
+		      1 + IntInf.log2 (IntInf.fromInt (String.size chars)))
+	 val r: word ref = ref (rand ())
+	 val count: int ref = ref 0
+	 val numChars = Word.fromInt (String.size chars)
       in
-	 fun alphaNumString (length: int) =
-	    String.tabulate
-	    (length, fn i =>
-	     let
-		val _ =
-		   if 0 = Int.rem (i, 6) (* n^6 = 62^6 = 965,660,736 *)
-		      then r := rand ()
-		   else ()
-		val w = !r
-		val c = String.sub (chars, Word.toInt (Word.mod (w, n)))
-		val _ = r := Word.div (w, n)
-	     in
-		c
-	     end)
+	 fun alphaNumChar (): char =
+	    let
+	       val n = !count
+	       val _ = if 0 = n then r := rand () else ()
+	       val w = !r
+	       val c = String.sub (chars, Word.toInt (Word.mod (w, numChars)))
+	       val _ = r := Word.div (w, numChars)
+	       val n = n + 1
+	       val _ = count := (if n = refresh then 0 else n)
+	    in
+	       c
+	    end
       end
+
+      fun alphaNumString (length: int): string =
+	 String.tabulate (length, fn _ => alphaNumChar ())
    end



1.4       +32 -26    mlton/lib/mlton-stubs/random.sml

Index: random.sml
===================================================================
RCS file: /cvsroot/mlton/mlton/lib/mlton-stubs/random.sml,v
retrieving revision 1.3
retrieving revision 1.4
diff -u -r1.3 -r1.4
--- random.sml	28 Dec 2003 22:45:36 -0000	1.3
+++ random.sml	28 Dec 2003 23:15:01 -0000	1.4
@@ -15,33 +15,39 @@
 	    end
 
 	 fun srand (w: word): unit = seed := w
-
-	 structure String =
-	    struct
-	       open String
+      end
+   
+      structure String =
+	 struct
+	    open String
 			
-	       val tabulate = CharVector.tabulate
-	    end
-	 local
-	    val chars =
-	       "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
-	    val n = Word.fromInt (String.size chars)
-	    val r: word ref = ref 0w0
-	 in
-	    fun alphaNumString (length: int) =
-	       String.tabulate
-	       (length, fn i =>
-		let
-		   val _ =
-		      if 0 = Int.rem (i, 6) (* n^6 = 62^6 = 965,660,736 *)
-			 then r := rand ()
-		      else ()
-		   val w = !r
-		   val c = String.sub (chars, Word.toInt (Word.mod (w, n)))
-		   val _ = r := Word.div (w, n)
-		in
-		   c
-		end)
+	    val tabulate = CharVector.tabulate
 	 end
+
+      local
+	 val chars =
+	    "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
+	 val refresh =
+	    Int.quot (Word.wordSize,
+		      1 + IntInf.log2 (IntInf.fromInt (String.size chars)))
+	 val r: word ref = ref (rand ())
+	 val count: int ref = ref 0
+	 val numChars = Word.fromInt (String.size chars)
+      in
+	 fun alphaNumChar (): char =
+	    let
+	       val n = !count
+	       val _ = if 0 = n then r := rand () else ()
+	       val w = !r
+	       val c = String.sub (chars, Word.toInt (Word.mod (w, numChars)))
+	       val _ = r := Word.div (w, numChars)
+	       val n = n + 1
+	       val _ = count := (if n = refresh then 0 else n)
+	    in
+	       c
+	    end
       end
+
+      fun alphaNumString (length: int): string =
+	 String.tabulate (length, fn _ => alphaNumChar ())
    end