[latex3-commits] [git/LaTeX3-latex3-latex3] master: Change \int_rand:nn (and rand_item functions) to better use the RNG (c83d05b)

Bruno Le Floch bruno at le-floch.fr
Fri Apr 27 19:37:18 CEST 2018


Repository : https://github.com/latex3/latex3
On branch  : master
Link       : https://github.com/latex3/latex3/commit/c83d05b3f8ad6778d756b1e08d095e16a3b7e23c

>---------------------------------------------------------------

commit c83d05b3f8ad6778d756b1e08d095e16a3b7e23c
Author: Bruno Le Floch <bruno at le-floch.fr>
Date:   Fri Apr 27 13:37:18 2018 -0400

    Change \int_rand:nn (and rand_item functions) to better use the RNG
    
    The RNG's low bits are not great, so use in priority its high bits.


>---------------------------------------------------------------

c83d05b3f8ad6778d756b1e08d095e16a3b7e23c
 l3kernel/l3fp-random.dtx                |   56 +++++++++++++++++++------------
 l3kernel/testfiles/m3expl001.luatex.tlg |    2 +-
 l3kernel/testfiles/m3expl001.ptex.tlg   |    2 +-
 l3kernel/testfiles/m3expl001.tlg        |    2 +-
 l3kernel/testfiles/m3expl001.uptex.tlg  |    2 +-
 l3kernel/testfiles/m3expl003.luatex.tlg |    2 +-
 l3kernel/testfiles/m3expl003.ptex.tlg   |    2 +-
 l3kernel/testfiles/m3expl003.tlg        |    2 +-
 l3kernel/testfiles/m3expl003.uptex.tlg  |    2 +-
 l3kernel/testfiles/m3rand001.lvt        |    2 +-
 l3kernel/testfiles/m3rand001.tlg        |   52 ++++++++++++++--------------
 11 files changed, 70 insertions(+), 56 deletions(-)

diff --git a/l3kernel/l3fp-random.dtx b/l3kernel/l3fp-random.dtx
index 439eb85..b05325e 100644
--- a/l3kernel/l3fp-random.dtx
+++ b/l3kernel/l3fp-random.dtx
@@ -334,21 +334,27 @@
 %
 % \begin{macro}{\int_rand:nn}
 % \begin{macro}{\@@_randint:ww}
+% \begin{macro}{\@@_randint_narrow:n}
 % \begin{macro}{\@@_randint_narrow:nn}
 % \begin{macro}{\@@_randint_narrow:nnn}
-% \begin{macro}{\@@_randint_narrow:nnnn}
 %   Evaluate the argument and filter out the case where the lower
 %   bound~|#1| is more than the upper bound~|#2|.  Then determine
-%   whether the range is narrower than \cs{c__fp_rand_size_int}; |#2-#1|
+%   whether the range is narrower than \cs{c_@@_rand_size_int}; |#2-#1|
 %   may overflow for very large positive~|#2| and negative~|#1|.  If the
 %   range is wide, use slower code from \pkg{l3fp}.  If the range is
-%   narrow, call \cs{@@_randint_narrow:nn} \Arg{choices} |{#1}| where
-%   \meta{choices} is the number of possible outcomes.  Then
-%   \cs{@@_randint_narrow:nnnn} receives a random number reduced modulo
-%   \meta{choices}, the random number itself, \meta{choices} and |#1|.
-%   To avoid bias, throw away the random number if it lies in the last,
-%   incomplete, interval of size \meta{choices} in
-%   $[0,\cs{c_@@_rand_size_int}-1]$, and try again.
+%   narrow, call \cs{@@_randint_narrow:n} \Arg{choices} where
+%   \meta{choices} is the number of possible outcomes.
+%
+%   One option then would be to reduce a random number modulo
+%   \meta{choices}, but the low-order bits of random numbers provided by
+%   the primitive have poor randomness: empirical tests indicate that
+%   taking random numbers modulo~$2$ gives only two possible sequences
+%   of bits depending on the seed's parity.  Instead, fit in the output
+%   range $[0,\cs{c_@@_rand_size_int}-1]$ of the random number generator
+%   \meta{choices} equal-size intervals of maximum possible size
+%   (obtained using \cs{int_div_truncate:nn}).  Given a random number,
+%   divide it by the size to determine which interval it falls into; if
+%   it is beyond \meta{choices}, try another random number.
 %    \begin{macrocode}
     \cs_new:Npn \int_rand:nn #1#2
       {
@@ -369,27 +375,35 @@
               { \int_compare:nNnTF { #2 - #1 } < \c_@@_rand_size_int }
               { \int_compare:nNnTF {#2} < { #1 + \c_@@_rand_size_int } }
                   {
-                    \exp_args:Nf \@@_randint_narrow:nn
-                      { \int_eval:n { #2 - #1 + 1 } } {#1}
+                    \int_eval:n
+                      {
+                        #1 +
+                        \exp_args:Nf \@@_randint_narrow:n
+                          { \int_eval:n { #2 - #1 + 1 } }
+                      }
                   }
                   { \fp_to_int:n { randint(#1,#2) } }
           }
       }
-    \cs_new:Npn \@@_randint_narrow:nn
+    \cs_new:Npn \@@_randint_narrow:n #1
       {
-        \exp_args:No \@@_randint_narrow:nnn
-          { \pdftex_uniformdeviate:D \c_@@_rand_size_int }
+        \exp_args:Nf \@@_randint_narrow:nn
+          { \int_div_truncate:nn \c_@@_rand_size_int {#1} } {#1}
       }
-    \cs_new:Npn \@@_randint_narrow:nnn #1#2
+    \cs_new:Npn \@@_randint_narrow:nn #1
       {
-        \exp_args:Nf \@@_randint_narrow:nnnn
-          { \int_mod:nn {#1} {#2} } {#1} {#2}
+        \exp_args:Nf \@@_randint_narrow:nnn
+          {
+            \int_div_truncate:nn
+              { \pdftex_uniformdeviate:D \c_@@_rand_size_int } {#1}
+          }
+          {#1}
       }
-    \cs_new:Npn \@@_randint_narrow:nnnn #1#2#3#4
+    \cs_new:Npn \@@_randint_narrow:nnn #1#2#3
       {
-        \int_compare:nNnTF { #2 - #1 + #3 } > \c_@@_rand_size_int
-          { \@@_randint_narrow:nn {#3} {#4} }
-          { \int_eval:n { #4 + #1 } }
+        \int_compare:nNnTF {#1} < {#3}
+          {#1}
+          { \@@_randint_narrow:nn {#2} {#3} }
       }
 %    \end{macrocode}
 % \end{macro}
diff --git a/l3kernel/testfiles/m3expl001.luatex.tlg b/l3kernel/testfiles/m3expl001.luatex.tlg
index 07f0464..d502a54 100644
--- a/l3kernel/testfiles/m3expl001.luatex.tlg
+++ b/l3kernel/testfiles/m3expl001.luatex.tlg
@@ -4183,9 +4183,9 @@ Defining \__fp_randint_wide_e:nnnn on line ...
 Defining \__fp_randint_wide_e:wnnn on line ...
 Defining \int_rand:nn on line ...
 Defining \__fp_randint:ww on line ...
+Defining \__fp_randint_narrow:n on line ...
 Defining \__fp_randint_narrow:nn on line ...
 Defining \__fp_randint_narrow:nnn on line ...
-Defining \__fp_randint_narrow:nnnn on line ...
 Defining \c__intarray_sp_dim on line ...
 \c__intarray_sp_dim=\dimen...
 Defining \g__intarray_font_int on line ...
diff --git a/l3kernel/testfiles/m3expl001.ptex.tlg b/l3kernel/testfiles/m3expl001.ptex.tlg
index fb54e7b..35543de 100644
--- a/l3kernel/testfiles/m3expl001.ptex.tlg
+++ b/l3kernel/testfiles/m3expl001.ptex.tlg
@@ -4437,9 +4437,9 @@ Defining \__fp_randint_wide_e:nnnn on line ...
 Defining \__fp_randint_wide_e:wnnn on line ...
 Defining \int_rand:nn on line ...
 Defining \__fp_randint:ww on line ...
+Defining \__fp_randint_narrow:n on line ...
 Defining \__fp_randint_narrow:nn on line ...
 Defining \__fp_randint_narrow:nnn on line ...
-Defining \__fp_randint_narrow:nnnn on line ...
 Defining \c__intarray_sp_dim on line ...
 \c__intarray_sp_dim=\dimen...
 Defining \g__intarray_font_int on line ...
diff --git a/l3kernel/testfiles/m3expl001.tlg b/l3kernel/testfiles/m3expl001.tlg
index dee9b8e..a6ffb80 100644
--- a/l3kernel/testfiles/m3expl001.tlg
+++ b/l3kernel/testfiles/m3expl001.tlg
@@ -4437,9 +4437,9 @@ Defining \__fp_randint_wide_e:nnnn on line ...
 Defining \__fp_randint_wide_e:wnnn on line ...
 Defining \int_rand:nn on line ...
 Defining \__fp_randint:ww on line ...
+Defining \__fp_randint_narrow:n on line ...
 Defining \__fp_randint_narrow:nn on line ...
 Defining \__fp_randint_narrow:nnn on line ...
-Defining \__fp_randint_narrow:nnnn on line ...
 Defining \c__intarray_sp_dim on line ...
 \c__intarray_sp_dim=\dimen...
 Defining \g__intarray_font_int on line ...
diff --git a/l3kernel/testfiles/m3expl001.uptex.tlg b/l3kernel/testfiles/m3expl001.uptex.tlg
index 10fcf3e..dda643b 100644
--- a/l3kernel/testfiles/m3expl001.uptex.tlg
+++ b/l3kernel/testfiles/m3expl001.uptex.tlg
@@ -4437,9 +4437,9 @@ Defining \__fp_randint_wide_e:nnnn on line ...
 Defining \__fp_randint_wide_e:wnnn on line ...
 Defining \int_rand:nn on line ...
 Defining \__fp_randint:ww on line ...
+Defining \__fp_randint_narrow:n on line ...
 Defining \__fp_randint_narrow:nn on line ...
 Defining \__fp_randint_narrow:nnn on line ...
-Defining \__fp_randint_narrow:nnnn on line ...
 Defining \c__intarray_sp_dim on line ...
 \c__intarray_sp_dim=\dimen...
 Defining \g__intarray_font_int on line ...
diff --git a/l3kernel/testfiles/m3expl003.luatex.tlg b/l3kernel/testfiles/m3expl003.luatex.tlg
index 07f0464..d502a54 100644
--- a/l3kernel/testfiles/m3expl003.luatex.tlg
+++ b/l3kernel/testfiles/m3expl003.luatex.tlg
@@ -4183,9 +4183,9 @@ Defining \__fp_randint_wide_e:nnnn on line ...
 Defining \__fp_randint_wide_e:wnnn on line ...
 Defining \int_rand:nn on line ...
 Defining \__fp_randint:ww on line ...
+Defining \__fp_randint_narrow:n on line ...
 Defining \__fp_randint_narrow:nn on line ...
 Defining \__fp_randint_narrow:nnn on line ...
-Defining \__fp_randint_narrow:nnnn on line ...
 Defining \c__intarray_sp_dim on line ...
 \c__intarray_sp_dim=\dimen...
 Defining \g__intarray_font_int on line ...
diff --git a/l3kernel/testfiles/m3expl003.ptex.tlg b/l3kernel/testfiles/m3expl003.ptex.tlg
index fb54e7b..35543de 100644
--- a/l3kernel/testfiles/m3expl003.ptex.tlg
+++ b/l3kernel/testfiles/m3expl003.ptex.tlg
@@ -4437,9 +4437,9 @@ Defining \__fp_randint_wide_e:nnnn on line ...
 Defining \__fp_randint_wide_e:wnnn on line ...
 Defining \int_rand:nn on line ...
 Defining \__fp_randint:ww on line ...
+Defining \__fp_randint_narrow:n on line ...
 Defining \__fp_randint_narrow:nn on line ...
 Defining \__fp_randint_narrow:nnn on line ...
-Defining \__fp_randint_narrow:nnnn on line ...
 Defining \c__intarray_sp_dim on line ...
 \c__intarray_sp_dim=\dimen...
 Defining \g__intarray_font_int on line ...
diff --git a/l3kernel/testfiles/m3expl003.tlg b/l3kernel/testfiles/m3expl003.tlg
index dee9b8e..a6ffb80 100644
--- a/l3kernel/testfiles/m3expl003.tlg
+++ b/l3kernel/testfiles/m3expl003.tlg
@@ -4437,9 +4437,9 @@ Defining \__fp_randint_wide_e:nnnn on line ...
 Defining \__fp_randint_wide_e:wnnn on line ...
 Defining \int_rand:nn on line ...
 Defining \__fp_randint:ww on line ...
+Defining \__fp_randint_narrow:n on line ...
 Defining \__fp_randint_narrow:nn on line ...
 Defining \__fp_randint_narrow:nnn on line ...
-Defining \__fp_randint_narrow:nnnn on line ...
 Defining \c__intarray_sp_dim on line ...
 \c__intarray_sp_dim=\dimen...
 Defining \g__intarray_font_int on line ...
diff --git a/l3kernel/testfiles/m3expl003.uptex.tlg b/l3kernel/testfiles/m3expl003.uptex.tlg
index 10fcf3e..dda643b 100644
--- a/l3kernel/testfiles/m3expl003.uptex.tlg
+++ b/l3kernel/testfiles/m3expl003.uptex.tlg
@@ -4437,9 +4437,9 @@ Defining \__fp_randint_wide_e:nnnn on line ...
 Defining \__fp_randint_wide_e:wnnn on line ...
 Defining \int_rand:nn on line ...
 Defining \__fp_randint:ww on line ...
+Defining \__fp_randint_narrow:n on line ...
 Defining \__fp_randint_narrow:nn on line ...
 Defining \__fp_randint_narrow:nnn on line ...
-Defining \__fp_randint_narrow:nnnn on line ...
 Defining \c__intarray_sp_dim on line ...
 \c__intarray_sp_dim=\dimen...
 Defining \g__intarray_font_int on line ...
diff --git a/l3kernel/testfiles/m3rand001.lvt b/l3kernel/testfiles/m3rand001.lvt
index 65b588a..73f163c 100644
--- a/l3kernel/testfiles/m3rand001.lvt
+++ b/l3kernel/testfiles/m3rand001.lvt
@@ -17,7 +17,7 @@
   {
     \sys_gset_rand_seed:n { 0 }
     \cs_new:Npn \test:n #1 { \prg_replicate:nn { 5 } { \fp_to_tl:n {#1} \NEWLINE } }
-    \cs_new:Npn \test_ii:n #1 { | \prg_replicate:nn { 5 } { #1 | } \NEWLINE }
+    \cs_new:Npn \test_ii:n #1 { | \prg_replicate:nn { 15 } { #1 | } \NEWLINE }
   }
   {
     \cs_new:Npn \test:n #1 { \fp_to_tl:n {#1} , ~ }
diff --git a/l3kernel/testfiles/m3rand001.tlg b/l3kernel/testfiles/m3rand001.tlg
index b037084..ff4d480 100644
--- a/l3kernel/testfiles/m3rand001.tlg
+++ b/l3kernel/testfiles/m3rand001.tlg
@@ -226,52 +226,52 @@ nan
 ============================================================
 TEST 4: Random integer in a range
 ============================================================
-|-1|-1|1|0|-1|
-|-2147483647|-2147483647|-2147483647|-2147483647|-2147483647|
-|-2147483645|-2147483644|-2147483638|-2147483647|-2147483644|
-|-758446477|1931291650|79608793|-160587022|1579678534|
+|0|-1|0|1|0|1|0|0|-1|1|-1|0|1|1|0|
+|-2147483647|-2147483647|-2147483647|-2147483647|-2147483647|-2147483647|-2147483647|-2147483647|-2147483647|-2147483647|-2147483647|-2147483647|-2147483647|-2147483647|-2147483647|
+|-2147483638|-2147483643|-2147483642|-2147483642|-2147483642|-2147483645|-2147483641|-2147483646|-2147483646|-2147483644|-2147483647|-2147483639|-2147483642|-2147483645|-2147483646|
+|-1383802119|1847464213|1896138077|1141097059|-1805716453|303683616|630789435|83660916|1553919714|2065890169|-143934675|-1879794472|-640520242|1146446601|-1026621466|
 ============================================================
 ============================================================
 TEST 5: Random tl item
 ============================================================
 ||
-|\A |\A |\A |\A |\A |
-| \B | \B | \B |\A |\A |
-|\C |{\B }|\C |\C |{\B }|
-||||||
-||||||
-||| | | |
-|\A |##|\A | |\A |
+|\A |\A |\A |\A |\A |\A |\A |\A |\A |\A |\A |\A |\A |\A |\A |
+|\A |\A | \B |\A | \B | \B | \B | \B | \B |\A | \B | \B | \B |\A | \B |
+|\C |\A |\C |\C |\A |{\B }|\A |{\B }|\C |{\B }|\A |\A |{\B }|\C |{\B }|
+||||||||||||||||
+||||||||||||||||
+| | | | | |||| | || | | ||
+| | | |\A |&|\A |##|##|##| |##|##|\A | |\A |
 ============================================================
 ============================================================
 TEST 6: Random clist item
 ============================================================
 ||
-|\A |\A |\A |\A |\A |
-|\A |{}|{}| \B | ,|
-||||||
-|| ,| ,|||
-|&|##|##|&|##|
+|\B |\A |\A |\B |\B |\B |\A |\B |\B |\A |\B |\B |\B |\A |\B |
+|{}|\A |\A |\A |\A |\A |\A |\A |\A | \B |\A |\A |{}|\A | ,|
+||||||||||||||||
+| ,|| ,|| ,|| ,||||| ,|| ,||
+|,|,|##|,|,|\\|##|,|&|\\|\\|##|,|,|,|
 ============================================================
 ============================================================
 TEST 7: Random seq item
 ============================================================
-||||||
-||| ,|||
-|{\\}|##|##|,|\A |
+||||||||||||||||
+| ,| ,| ,|| ,| ,| ,||| ,| ,||| ,||
+|,|\A |##|&|\A |,|\A |\A |,|##|\A |\A |##|&|##|
 ============================================================
 ============================================================
 TEST 8: Random prop key/value
 ============================================================
-||||||
-|{\a }{\A }|{\e }{}|{\b }{{\B }}|{\b }{{\B }}|{\a }{\A }|
+||||||||||||||||
+|{\a }{\A }|{\b }{{\B }}|{\a }{\A }|{\e }{}|{\a }{\A }|{\a }{\A }|{\b }{{\B }}|{\e }{}|{\a }{\A }|{\a }{\A }|{\a }{\A }|{\e }{}|{\b }{{\B }}|{\a }{\A }|{\a }{\A }|
 ============================================================
 ============================================================
 TEST 9: sys rand commands
 ============================================================
-1,30
-0,89
-0,79
-1,30
-1,8
+1,71
+0,25
+0,73
+1,71
+1,10
 ============================================================





More information about the latex3-commits mailing list