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}