How to Obtain a Random Non-Zero Integer?

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}

• 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! Jan 5, 2017 at 11:36

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):

\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}

• 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

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}


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}


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}


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}


(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.

% !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}


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:

• 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