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

14

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

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .