高斯随机数

高斯随机数

Tikz 手册中有各种不同的数学选项,但以下是第一个真正有效的版本。有没有更好的方法可以做到这一点?

\documentclass{article}
\usepackage{tikz}

\usetikzlibrary{calc}

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

\def\gauss{
 \advance\gaussF by 1\relax
 \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}

答案1

我不确定问题中的算法是否正确,但它肯定是以次优方式实现的。虽然杰克(现已删除)的答案是可读的,但它也有一个巨大的在函数内部调用解析器的开销。

使用较低级别的宏非常简单pgfmath(尽管我可能应该这么说)。

无论哪种方式,在两种情况下,rnd都会在间隔上产生伪随机数,因此必须处理[0,1]的可能性。ln(0)

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

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

\makeatletter
\pgfmathdeclarefunction{gaussR}{0}{%
 \global\advance\gaussF by 1\relax
 \ifodd\gaussF
  \pgfmathrnd@%
  \ifdim\pgfmathresult pt=0.0pt\relax%
    \def\pgfmathresult{0.00001}%
  \fi
  \pgfmathln@{\pgfmathresult}%
  \pgfmathmultiply@{-2}{\pgfmathresult}%
  \pgfmathsqrt@{\pgfmathresult}%
  \global\let\gaussR=\pgfmathresult%radius
  \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}%
  \let\@radius=\pgfmathresult%
  \pgfmathmultiply{6.28318531}{#2}% <- might need parsing
  \pgfmathdeg@{\pgfmathresult}%
  \pgfmathcos@{\pgfmathresult}%
  \pgfmathmultiply@{\pgfmathresult}{\@radius}%
}

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

在此处输入图片描述

答案2

在此处输入图片描述

我定义了一个函数randomNormal,它接受一个参数,即方差,并返回一个平均值为 0 的高斯随机数。它是使用math库编写的,因此只需要一行代码。数学公式是问题和 @Mark Wibrow 的答案中出现的公式。

代码

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

相关内容