10

I try to create a table with random entries... By browsing the tag, I found some help on random number generators and I tried using lcg.

Surprisingly I seem to create the same random number over and over again, whatever I choose as seed... does anyone have a clue?

Code for a 5x5 table:

\chgrand[first=0, last=4, counter=kids]
\begin{tabular}{rrrrr}
\forloop{row_number}{1}{\value{row_number} < 6}{%%
    \forloop{col_number}{1}{\value{col_number} < 5}{%%%
       \rand\arabic{kids} & 
    }%%%
    \rand\arabic{kids}
    \\ }%%
\end{tabular}

creates:

4 4 4 4 4
4 4 4 4 4
4 4 4 4 4
4 4 4 4 4
4 4 4 4 4

doesn't look random to me...

I tried changing \rand to \rand\rand and all entries changed to '3'. So I presume every time I call \rand it starts back from the same seed, but I don't see why, as the seed is declared before the \forloop. Or isn't it?

  • 10
    This seems appropriate, while looking for an answer dilbert.com/dyn/str_strip/000000000/00000000/0000000/000000/… – egreg Oct 24 '12 at 21:22
  • Probably your \forloop puts a group around the body. Package lcg uses local assignments, thus the internal state is reset after the group. – Heiko Oberdiek Oct 24 '12 at 21:28
  • i could add something like \chgrand[seed=\value{rand}] inside the \forloop, but that hardly seems a workaround to me (i guess that would lead to the same re-occuring sequence over and over again) – long tom Oct 24 '12 at 21:28
  • @HeikoOberdiek: so i'd have to change to \foreach? or to another random number generator? – long tom Oct 24 '12 at 21:30
  • \foreach of pgf also puts a group around the loop body. – Heiko Oberdiek Oct 24 '12 at 21:32
11

The problem is that you're doing that inside a table cell and TeX doesn't like it very much. It's better to build up the token list before doing the table:

\documentclass{article}
\usepackage{lcg,forloop}
\newtoks\dierckxtoks
\newcounter{row_number}\newcounter{col_number}

\begin{document}

\chgrand[first=0, last=4, counter=kids]
\dierckxtoks={}

\forloop{row_number}{1}{\value{row_number} < 6}{% 
  \forloop{col_number}{1}{\value{col_number} < 5}{%  
     \rand
     \edef\x{\the\dierckxtoks\arabic{kids} &}
     \dierckxtoks\expandafter{\x}%
  }%  
  \rand
  \edef\x{\the\dierckxtoks\arabic{kids} \noexpand\\}
  \dierckxtoks\expandafter{\x}%
}  

\begin{tabular}{rrrrr}
\the\dierckxtoks
\end{tabular}

\end{document}

enter image description here

On the other hand, as shown in my first comment, also 444444444 can be a sequence of random numbers. :-)


The mandatory expl3 solution.

\documentclass{article}
\usepackage{lcg}
\newcounter{randnumb}
\usepackage{xparse}
\ExplSyntaxOn
\NewDocumentCommand{\randomtabular}{ O{randnumb} m m m m }
% #1 = counter name (optional default randnumb)
% #2 = lowest value
% #3 = highest value
% #4 = rows
% #5 = columns
 {
  \chgrand[first=#2, last=#3, counter=#1]
  \dierckx_random_tabular:nnn {#1}{#4}{#5}
 }
\tl_new:N \l_dierckx_tabular_tl
\cs_new_protected:Npn \dierckx_random_tabular:nnn #1 #2 #3
 {
  \tl_clear:N \l_dierckx_tabular_tl
  \prg_replicate:nn { #2 }
   {
    \prg_replicate:nn { #3 - 1 }
     {
      \rand
      \tl_put_right:Nx \l_dierckx_tabular_tl { \arabic{#1} & }
     }
    \rand
    \tl_put_right:Nx \l_dierckx_tabular_tl { \arabic{#1} }
    \tl_put_right:Nn \l_dierckx_tabular_tl { \\ }
   }
  \begin{tabular}{*{#3}{r}}
  \l_dierckx_tabular_tl
  \end{tabular}
 }
\ExplSyntaxOff

\begin{document}

\randomtabular{0}{9}{6}{4}

\randomtabular[kids]{0}{4}{5}{5}

\end{document}

enter image description here


A different solution using the random number facility of pgf:

\documentclass{article}
\usepackage{pgf}
\usepackage{xparse}
\ExplSyntaxOn
\NewDocumentCommand{\randomtabular}{ m m m m }
% #1 = lowest value
% #2 = highest value
% #3 = rows
% #4 = columns
 {
  \dierckx_random_tabular:nnnn {#1}{#2}{#3}{#4}
 }
\tl_new:N \l__dierckx_tabular_tl
\int_new:N \l__dierckx_random_number_int
\cs_new_protected:Npn \dierckx_random_tabular:nnnn #1 #2 #3 #4
 {
  \tl_clear:N \l_dierckx_tabular_tl
  \prg_replicate:nn { #3 }
   {
    \prg_replicate:nn { #4 - 1 }
     {
      \dierckx_get_rand:nn { #1 } { #2 }
      \tl_put_right:Nx \l_dierckx_tabular_tl { \int_to_arabic:n { \l__dierckx_random_number_int } & }
     }
    \dierckx_get_rand:nn { #1 } { #2 }
    \tl_put_right:Nx \l_dierckx_tabular_tl { \int_to_arabic:n { \l__dierckx_random_number_int } }
    \tl_put_right:Nn \l_dierckx_tabular_tl { \\ }
   }
  \begin{tabular}{*{#3}{r}}
  \l_dierckx_tabular_tl
  \end{tabular}
 }
\cs_new_protected:Npn \dierckx_get_rand:nn #1 #2
 {
  \pgfmathrandominteger{ \l__dierckx_random_number_int } { #1 } { #2 }
 }
\ExplSyntaxOff

\begin{document}

\randomtabular{0}{9}{6}{4}

\bigskip

\randomtabular{0}{4}{5}{5}

\end{document}

There is no optional argument any more, but it doesn't seem to be really necessary.


A variant of the first expl3 solution that pads the number with zeros to have the same length as the highest possible chosen number.

\documentclass{article}
\usepackage{lcg}
\newcounter{randnumb}
\usepackage{xparse}
\ExplSyntaxOn
\NewDocumentCommand{\randomtabular}{ O{randnumb} m m m m }
% #1 = counter name (optional default randnumb)
% #2 = lowest value
% #3 = highest value
% #4 = rows
% #5 = columns
 {
  \int_set:Nn \l_dierckx_padto_int { \tl_count:n { #3 } }
  \chgrand[first=#2, last=#3, counter=#1]
  \dierckx_random_tabular:nnn {#1}{#4}{#5}
 }
\tl_new:N \l_dierckx_tabular_tl
\tl_new:N \l_dierckx_temp_tl
\int_new:N \l_dierckx_padto_int

\cs_new_protected:Npn \__dierckx_padnumber:nn #1 #2
 {
  \tl_set:Nx \l_dierckx_temp_tl { \arabic{#1} }
  \tl_set:Nx \l_dierckx_temp_tl
   {
    \prg_replicate:nn { \l_dierckx_padto_int - \tl_count:N \l_dierckx_temp_tl } { 0 }
    \l_dierckx_temp_tl
   }
  \tl_put_right:Nx \l_dierckx_tabular_tl { \l_dierckx_temp_tl #2 }
 }

\cs_new_protected:Npn \dierckx_random_tabular:nnn #1 #2 #3
 {
  \tl_clear:N \l_dierckx_tabular_tl
  \prg_replicate:nn { #2 }
   {
    \prg_replicate:nn { #3 - 1 }
     {
      \rand
      \__dierckx_padnumber:nn { #1 } { & }
     }
    \rand
    \__dierckx_padnumber:nn { #1 } { }
    \tl_put_right:Nn \l_dierckx_tabular_tl { \\ }
   }
  \begin{tabular}{*{#3}{r}}
  \l_dierckx_tabular_tl
  \end{tabular}
 }
\ExplSyntaxOff

\begin{document}

\randomtabular{0}{100000}{6}{4}

\end{document}

enter image description here

  • I do accept 4444...4 to be a possible random sequence... but... with a 2^31 space for seed the odds to get this sequence with a random seed are about 0.3E-8. And i tried different seeds... besides, as \rand\rand changed the complete table, one can be pretty sure something was wrong. But I'm glad someone pointed me on what exactly was wrong... – long tom Oct 25 '12 at 8:34
  • i dropped the second part of code in a .sty file. so i'm able to reuse them from now on. – long tom Oct 25 '12 at 9:18
  • If you choose the max number as, say 100 000, how can you get the random numbers to print zeros for numbers like 00257 and 03498? – azetina Apr 20 '15 at 19:40
  • @azetina There should be a question about padding a number with zeros. – egreg Apr 20 '15 at 19:41
  • @egreg Let me search and see what I can find about padding with zeros. I was about to ask about how to create a random number table for a statistics class I am teaching and I stumbled upon your answer. Am amazed as to how you achieved it. I am still a little puzzled as to some parts of the expl3 coding but I will look into it before I make further comments. Thanks :) – azetina Apr 20 '15 at 19:44
10

I made a quick tikz solution. You may use \pgfmathsetseed{} for repeatable results.

\documentclass{article}

\usepackage{tikz}

\begin{document}
\begin{tikzpicture}
    \foreach \x in {1,...,5}{
        \foreach \y in {1,...,5}{
        \pgfmathrandominteger{\a}{0}{4}
            \node at (\x/2,\y/2){\a};
        }
    }
\end{tikzpicture}


\end{document}

result:

screenshot

1

Here is a short example. The \tal command generates a random number. The \sekscifret command uses \tal and generates and writes a number with 6 digits. The loop inside the table inserts such numbers in columns and rows.

\documentclass{article}

\usepackage[english]{babel}
\usepackage{lcg}
\usepackage{forloop}

\newcounter{ct}
\newcounter{ctA}
\newcommand{\tal}{\chgrand[first=0,last=9,counter=randTal]\rand\arabic{randTal}}
\newcommand{\sekscifret}{\forloop{ct}{1}{\value{ct} < 7}{\tal}}

\begin{document}

\begin{tabular}{r r r r}

\forloop{ctA}{1}{\value{ctA} < 7}{

\sekscifret&\sekscifret&\sekscifret&\sekscifret
\\}

\end{tabular}

\end{document}

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.