# Gaussian random numbers

The Tikz manual has all sorts of different options regarding math, but the following is the first version which actually worked. Is there a better way to do this?

\documentclass{article}
\usepackage{tikz}

\usetikzlibrary{calc}

\newcount\gaussF
\edef\gaussR{0}
\edef\gaussA{0}

\def\gauss{
\ifodd\gaussF
\pgfmathrnd
\edef\temp{\pgfmathresult}
\pgfmathln{\temp}
\edef\temp{\pgfmathresult}
\pgfmathmultiply{-2}{\temp}
\edef\temp{\pgfmathresult}
\pgfmathsqrt{\temp}
\edef\gaussR{\pgfmathresult}%radius = $sqrt(-2*ln(rnd))$
\pgfmathrnd
\edef\temp{\pgfmathresult}
\pgfmathmultiply{360}{\temp}
\edef\gaussA{\pgfmathresult}%angle = $360*rnd$
\pgfmathcos{\gaussA}
\edef\temp{\pgfmathresult}
\pgfmathmultiply{\gaussR}{\temp}
\else
\pgfmathsin{\gaussA}
\edef\temp{\pgfmathresult}
\pgfmathmultiply{\gaussR}{\temp}
\fi
\pgfmathresult
}

\begin{document}

\noindent
\gauss\\
\gauss\\
\gauss\\
\gauss

\end{document}

• A better way to do what? What are "Gaussian random numbers"? What is wrong with the random numbers of PGFmath? What does not work without your code? Why are you loading TikZ and its calc library? Is this question about PGFmath? Commented Dec 2, 2013 at 23:42
• I went through a lot of versions using different constructs before this one, generating a host of obtuse error messages and/or no numbers. Gaussian (normally distributed) random numbers can take on any value from -\infty to +\infty (unlike rnd which is uniformly distributed). Pgfmath is part of Tikz, and I originally intended to graph the results. And yes, this is a question about pgfmath. Commented Dec 3, 2013 at 4:56
• I don't know why do you need this. But in this kind of problems, I thinck it's MUCH better to calculate the numbers only ONCE with another program, and input into the document. Commented Dec 3, 2013 at 8:54
• @JohnKormylo: You don't need the calc library for using pgfmath. calc is for coordinate calculations (like ($(0,0)+(2,2)$).
– Jake
Commented Dec 3, 2013 at 9:13
• @Jake As I said, I don't know the context. But in the end you will have one document. Why ask latex to calculate random numbers every compilation instead of calculate them once and then input them. I think it's more “clean” and “logical” that way. Commented Dec 3, 2013 at 9:31

I'm not sure that the algorithm in the question is correct, nevertheless it is certainly implemented in a sub-optimal manner. Although Jake's (now deleted) answer is readable it also has a huge overhead in calling the parser inside a function.

It is quite simple to use the lower level pgfmath macros (although I probably would be expected to say that).

Either way, in both cases, rnd produces pseudo-random numbers on the interval [0,1] so the possibility of ln(0) must be dealt with.

\documentclass[border=0.125cm]{standalone}
\usepackage{tikz}

\newcount\gaussF
\edef\gaussR{0}
\edef\gaussA{0}

\makeatletter
\pgfmathdeclarefunction{gaussR}{0}{%
\ifodd\gaussF
\pgfmathrnd@%
\ifdim\pgfmathresult pt=0.0pt\relax%
\def\pgfmathresult{0.00001}%
\fi
\pgfmathln@{\pgfmathresult}%
\pgfmathmultiply@{-2}{\pgfmathresult}%
\pgfmathsqrt@{\pgfmathresult}%
\pgfmathrnd@%
\pgfmathmultiply@{360}{\pgfmathresult}%
\global\let\gaussA=\pgfmathresult%angle
\pgfmathcos@{\pgfmathresult}%
\pgfmathmultiply@{\pgfmathresult}{\gaussR}%
\else
\pgfmathsin@{\gaussA}%
\pgfmathmultiply@{\gaussR}{\pgfmathresult}%
\fi
}

\pgfmathdeclarefunction{invgauss}{2}{%
\pgfmathln{#1}% <- might need parsing
\pgfmathmultiply@{\pgfmathresult}{-2}%
\pgfmathsqrt@{\pgfmathresult}%
\pgfmathmultiply{6.28318531}{#2}% <- might need parsing
\pgfmathdeg@{\pgfmathresult}%
\pgfmathcos@{\pgfmathresult}%
}

\pgfmathdeclarefunction{randnormal}{0}{%
\pgfmathrnd@
\ifdim\pgfmathresult pt=0.0pt\relax%
\def\pgfmathresult{0.00001}%
\fi%
\let\@tmp=\pgfmathresult%
\pgfmathrnd@%
\ifdim\pgfmathresult pt=0.0pt\relax%
\def\pgfmathresult{0.00001}%
\fi
\pgfmathinvgauss@{\pgfmathresult}{\@tmp}%
}

\begin{document}

\begin{tikzpicture}[x=10pt,y=10pt]
\foreach \i in {0,...,2000}
\fill [opacity=1/10] (randnormal, randnormal) circle [radius=1/10];
\tikzset{shift=(0:10)}
\foreach \i  in {0,...,2000}
\fill [blue, opacity=1/10] (gaussR, gaussR) circle [radius=1/10];
\end{tikzpicture}

\end{document}


• It would be a lot easier if they were in the manual. And the algorithm is valid (you can find it in Numerical Recipes in C). Two Gaussian distributions in rectangular coordinates when converted to polar coordinates give an exponential in r^2 and uniform in angle. Commented Dec 3, 2013 at 15:32
• I see that randnormal uses the same algorithm, except that it only uses the cosine component. Commented Dec 3, 2013 at 16:04
• What exactly does \pgfmathdeg@ do? You also might be interested in my essay elfsoft2000.com/reports/sines.pdf Commented Dec 3, 2013 at 16:23
• @JohnKormylo The manual describes how every function (e.g., myfunc) declared with \pgfmathdeclarefunction defines a macro (e.g., \pgfmathmyfunc) which takes the required number of arguments, which are then parsed and passed onto the internal macro (i.e., \pgfmathmyfunc@) which takes the same number of arguments but they are expected to be completely parsed numbers without units (which is what the parser provides). The code provided as the last argument to \pgfmathdeclarefunction works with these parsed arguments to perform the calculation. Commented Dec 3, 2013 at 17:58
• @JohnKormylo in fact the deg function is unnecessary. I've updated the answer. Commented Dec 3, 2013 at 18:07

I defined the function randomNormal which takes one argument, the variance, and returns a Gaussian random number with average 0. It is written using the math library, so it needs only one line of code. The mathematical formula is the one appearing in the question and @Mark Wibrow 's answer.

The code

\documentclass[11pt, margin=.5cm]{standalone}
\usepackage{tikz}
\usetikzlibrary{math, calc}

\begin{document}
\tikzmath{%
function randomNormal(\s) {  % variance
return {sin(360*rnd)*sqrt(-2*\s*ln(rnd))};
};
}
\begin{tikzpicture}
\foreach \s/\rgb [count=\i from 0] in {0.3/violet, 0.65/blue, 1/green!70!black}{
\draw (-2 +5*\i,  0) -- ++(4, 0);
\draw (5*\i,  -1.5) -- ++(0, 3);

\foreach \k in {1, 2, ..., 1000}{%
\filldraw[\rgb, opacity=.1]
($(5*\i, 0) +({randomNormal(\s)}, {randomNormal(\s)})$) circle (2pt);
}
\path (5*\i,  -2.5) node {variance=\s};
}
\end{tikzpicture}

\end{document}