13

I would like \a to generate a random non-zero integer between, say, -5 and 5 inclusively.

One way to do this would be to make a list of all integers from -5 to 5 but excluding zero, then drawing randomly from that list. This is OK, but would not scale very well if I wanted \a to be a non-zero integer between, say, -500 and 500.

Is there an easier adjustment to make to the following code to specifically exclude the possibility of \a=0?

\documentclass{article}

\usepackage{ifthen}
\usepackage{pgf}
 \pgfmathsetseed{\number\pdfrandomseed}

\newcommand{\InitVariables}
{\pgfmathsetmacro{\a}{int(random(0,10)-5)}}

\begin{document}

\InitVariables

\a

\end{document}
2
  • 2
    It is best not to use \a which is a core latex command. Jan 4, 2017 at 19:50
  • Very good to know! When I became a professor, I'll use random numbers to make students exams!
    – Red Banana
    Jan 5, 2017 at 11:36

5 Answers 5

13

Choose a random number between 1 and X (thereby avoiding 0) and multiply it with 1 or -1 based on a uniform distribution (thereby obtaining a sign):

enter image description here

\documentclass{article}

\usepackage{tikz}
\pgfmathsetseed{\number\pdfrandomseed}

\newcommand{\InitVariables}{%
  \pgfmathsetmacro{\a}{int(ifthenelse(rand > 0, 1, -1)*random(1,5))}%
}

\begin{document}

\foreach \x in {1,...,100}{\InitVariables$\a$ }

\end{document}
4
  • The hack seems amazingly simple in concept. I don't quite understand the syntax of the ifthenelse part. How did that work? Jan 10, 2017 at 4:59
  • @WeCanLearnAnything: ifthenelse(<test>,<true>,<false>). So we randomly multiply a random number between 1 and 5 - random(1,5) by +1 or -1.
    – Werner
    Jan 10, 2017 at 5:02
  • what is rand? Is that some kind of command already built in? Jan 10, 2017 at 5:29
  • @WeCanLearnAnything: Yes. It returns a number between -1 and 1 with uniform distribution. See section 89.3.6 Pseudo-random functions (p 935) of the pgf [documentation](mirrors.ctan.org/graphics/pgf/base/doc/pgfmanual.pdf).
    – Werner
    Jan 10, 2017 at 5:35
9

The first calculation only chooses the number of random values that are needed. The inclusive range [-5, 5] without 0 has 10 values.

\pgfmathsetmacro{\a}{random(0,9)-5}% range [-5, 4]

Then the negative values are in the correct range. The non-negative values are increased by one to move the range [0, 4] to [1, 5].

\pgfmathsetmacro{\a}{int(ifthenelse(\a<0, \a, \a + 1)}%

Full example:

\documentclass{article}
\usepackage{pgf}
\usepackage{pgffor}
\pgfmathsetseed{\number\pdfrandomseed}

\newcommand{\InitVariables}{%
  \pgfmathsetmacro{\a}{random(0,9)-5}%
  \pgfmathsetmacro{\a}{int(ifthenelse(\a<0, \a, \a + 1)}%
}

\begin{document}

\noindent
\foreach \i in {0, ..., 200} {%
  \InitVariables
  \a\space
}

\end{document}

Result

Version with the minimum and maximum values as macros:

\documentclass{article}

\usepackage{pgf}
\usepackage{pgffor}
\pgfmathsetseed{\number\pdfrandomseed}

\newcommand*{\RandomMinimum}{-300}
\newcommand*{\RandomMaximum}{700}

\newcommand*{\InitVariables}{%
  \pgfmathsetmacro{\a}{%
     \RandomMinimum + random(0, int(\RandomMaximum - int(\RandomMinimum)))
  }%
  \pgfmathtruncatemacro{\a}{ifthenelse(\a<0, \a, \a + 1}%
}

\begin{document}

\noindent
\foreach \i in {0, ..., 200} {%
  \InitVariables
  \a\space
}

\end{document}

Result

6

Generate a number between 0 and 2​x –1, then normalize it: if it is less than x, subtract x, otherwise subtract x and add 1.

\documentclass{article}

\newcommand{\randomdef}[2]{%
  \edef#1{%
    \expandafter\randomdefnormalize\pdfuniformdeviate\numexpr#2*2\relax\foo{#2}%
  }%
}
\def\randomdefnormalize#1\foo#2{%
  \ifnum#1<#2
    \the\numexpr#1-#2\relax
  \else
    \the\numexpr#1-#2+1\relax
  \fi
}

\begin{document}

\randomdef{\arandom}{5}$\arandom$,\space\randomdef{\arandom}{5}$\arandom$,\space
\randomdef{\arandom}{5}$\arandom$,\space\randomdef{\arandom}{5}$\arandom$,\space
\randomdef{\arandom}{5}$\arandom$,\space\randomdef{\arandom}{5}$\arandom$,\space
\randomdef{\arandom}{5}$\arandom$,\space\randomdef{\arandom}{5}$\arandom$,\space
\randomdef{\arandom}{5}$\arandom$,\space\randomdef{\arandom}{5}$\arandom$,\space
\randomdef{\arandom}{5}$\arandom$,\space\randomdef{\arandom}{5}$\arandom$,\space
\randomdef{\arandom}{5}$\arandom$,\space\randomdef{\arandom}{5}$\arandom$,\space
\randomdef{\arandom}{5}$\arandom$,\space\randomdef{\arandom}{5}$\arandom$

\end{document}

enter image description here

The same can of course be done with PGF features.

With xparse and expl3; also an interface to expandably get the number in the required interval. Here I use a different strategy: the random number is generated in the interval –x, x –1; if it's positive, I add 1.

\documentclass{article}
\usepackage{xparse}

\ExplSyntaxOn
\NewDocumentCommand{\randomdef}{mm}
 {
  \wcla_random_def:Nn #1 { #2 }
 }
\DeclareExpandableDocumentCommand{\randomget}{m}
 {
  \wcla_random_get:n { #1 }
 }
\cs_new_protected:Nn \wcla_random_def:Nn
 {
  \cs_set:Npx #1 { \wcla_random_get:n { #2 } }
 }
\cs_new:Nn \wcla_random_get:n
 {
  \__wcla_random_get:f { \fp_eval:n { randint(-#1,#1-1) } }
 }
\cs_new:Nn \__wcla_random_get:n
 {
  \int_compare:nTF { #1 < 0 } { #1 } { \fp_eval:n { #1+1 } }
 }
\cs_generate_variant:Nn \__wcla_random_get:n { f }
\ExplSyntaxOff

\begin{document}

\randomdef{\arandom}{5}$\arandom$,\space\randomdef{\arandom}{5}$\arandom$,\space
\randomdef{\arandom}{5}$\arandom$,\space\randomdef{\arandom}{5}$\arandom$,\space
\randomdef{\arandom}{5}$\arandom$,\space\randomdef{\arandom}{5}$\arandom$,\space
\randomdef{\arandom}{5}$\arandom$,\space\randomdef{\arandom}{5}$\arandom$,\space
\randomdef{\arandom}{5}$\arandom$,\space\randomdef{\arandom}{5}$\arandom$,\space
\randomdef{\arandom}{5}$\arandom$,\space\randomdef{\arandom}{5}$\arandom$,\space
\randomdef{\arandom}{5}$\arandom$,\space\randomdef{\arandom}{5}$\arandom$,\space
\randomdef{\arandom}{5}$\arandom$,\space\randomdef{\arandom}{5}$\arandom$

$\randomget{5}$, $\randomget{5}$, $\randomget{5}$, $\randomget{5}$,
$\randomget{5}$, $\randomget{5}$, $\randomget{5}$, $\randomget{5}$,
$\randomget{5}$, $\randomget{5}$, $\randomget{5}$, $\randomget{5}$,
$\randomget{5}$, $\randomget{5}$, $\randomget{5}$, $\randomget{5}$

\end{document}

enter image description here

6

(Don't use \a as the macro name since, as David Carlisle has noted in a comment, \a is the name of a core LaTeX command.)

For good measure, here's a LuaLaTeX-based solution. It sets up a Lua function named randnzint (short for "random non-zero integer", I suppose) that does the actual work, a LaTeX helper macro that makes it straightforward to call the Lua function, and a handful of demos of how to use the Lua function and the LaTeX helper macro.

The Lua function calculates its output by multiplying a randomly drawn integer between 1 and n with a randomly drawn 'dummy' variable that's equal to either 1 or -1.

enter image description here

% !TeX program = lualatex
\documentclass{article}

\usepackage{luacode}
\begin{luacode}
function randnzint ( n )
  return ( math.random(n) * (math.random(2)-1.5)*2 )
end
\end{luacode}
% LaTeX macro that calls the Lua function with an integer arg.
\newcommand\randnzint[1]{\directlua{tex.sprint( '$' .. randnzint(#1) .. '$')}}

\begin{document}
% directlua call to Lua function 'randnzint'
\directlua{tex.sprint(randnzint(5))} 

% invoke LaTeX helper macro '\randnzint' with various arguments
\randnzint{10} \randnzint{100} \randnzint{1000}

% generate 50 pretty-printed numbers between -5 and 5 (excl. 0)
\directlua{for i=1,50 do 
              tex.sprint('$'..randnzint(5)..'$ ') 
           end}
\end{document}
5

Perhaps a recursive definition of \InitVariables?

\documentclass{article}
\usepackage{ifthen}
\usepackage{tikz}
\pgfmathsetseed{\number\pdfrandomseed}

\newcommand{\InitVariables}
{\pgfmathsetmacro{\a}{int(random(1,10)-5)}%
\ifnum\a=0%
\InitVariables%
\fi}

\begin{document}

\foreach \x in {1,...,100}{\InitVariables\a}

\end{document}

With 1000 runs of the loop, and a ! added. No zeros around:

enter image description here

2
  • This looks good! Is there a reasonably easy way for me to understand what \typeout{\a} means? I don't think I've ever heard of that command before... and Google searching it led to some explanations that were over my head. Jan 4, 2017 at 19:03
  • @WeCanLearnAnything I think it just writes its argument to the .log file. So it's irrelevant really, just meant to demonstrate that zeros occur, but are discarded. Jan 4, 2017 at 19:05

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.