我正在使用 pgf 創建一些隨機考試。為了設定種子,我使用 pgfmathsetseed。該系統對種子使用非常不同的值,其範圍可能達到數千。 pgf 手冊說 pgfmathsetseed 接收整數,並且沒有任何限制。但是,我對不同的種子得到了完全相同的結果。下面的程式碼說明了這個問題:
\documentclass[letterpaper,9pt]{article}
\usepackage{tikz} % also for pgfmathparse
\usepackage{pgfmath} % also for pgfmathparse
\usepackage{siunitx} % also for pgfmathparse
\usepgflibrary{fpu}
\pgfkeys{/pgf/fpu}
\pgfkeys{/pgf/fpu/output format=sci}
\pgfkeys{/pgf/number format/.cd, sci, sci e, sci zerofill, precision = 3}
\newcommand{\example}[1]{%
\pgfmathsetseed{#1}
\pgfmathsetmacro{\FACTOR}{0.90} % constrol the randomness span
\pgfmathrandominteger{\NA}{1}{9}
\pgfmathsetmacro{\LAA}{2.0*(1 + \FACTOR*rand)}
\begin{tabular}{ccc}
#1 & \Num{\NA} & \Num{\LAA}
\end{tabular}
}
\newcommand{\Num}[1]{\pgfmathprintnumberto{#1}{\tmpnum}\ensuremath{\num{\tmpnum}}}
\begin{document}
\example{92}
\example{96}
\example{90}
\example{1}
\example{2}
\end{document}
輸出就像
92 1.000 1.576
96 1.000 1.576
90 1.000 1.576
1 7.000 2.245
2 4.000 6.891 × 10−1
正如您所看到的,對於多個種子來說,值是相同的。可以放入 pgfmathsetseed 的整數有限制嗎?或者說有什麼問題呢?謝謝。
答案1
隨機數的產生取決於以下中的一些初始參數pgfmathfunctions.random.code.tex
:
\def\pgfmath@rnd@a{69621}
\def\pgfmath@rnd@r{23902}
\def\pgfmath@rnd@q{30845}
我記得(我沒有檢查過),參數值是從 Press 等人的 C 數位參考文獻第二版中收集的。建議替代方案(也在 的評論中列出pgfmathfunctions.random.code.tex
)。
這些參數可以更改,例如,更改為與 Erich Janka 的參數相同的參數LCG封裝(pgf隨機的東西是基於它的),這可能會產生更理想的結果(儘管重複可能仍然發生在連續種子的序列中)
\documentclass{ltxdoc}
\usepackage{geometry}
\parindent=0pt
\usepackage{pgfmath,pgffor,lcg,xcolor,multicol}
\makeatletter
\def\pgfmath@rnd@a{16807}
\def\pgfmath@rnd@r{2836}
\def\pgfmath@rnd@q{127773}
\makeatother
\newcounter{lcgresult}
\newcommand{\example}[1]{%
\pgfmathsetseed{#1}%
\reinitrand[seed=#1, counter=lcgresult, first=1, last=9]
\xdef\pgfseq{}%
\xdef\lcgseq{}%
\foreach\s in{0,...,10}{%
\pgfmathrandominteger{\r}{1}{9}
\xdef\pgfseq{\pgfseq\space\r}
\rand
\xdef\lcgseq{\lcgseq\space\thelcgresult}
}%
\begin{tabular}{p{0.5cm}p{4cm}}
#1\hfil & \textcolor{blue}{\pgfseq} \newline \lcgseq
\end{tabular}%
}
\begin{document}
\begin{multicols}{3}
\foreach \i in {1,...,60}{\example{\i}}
\end{multicols}
\end{document}
答案2
這裡似乎有問題:顯然只有第一位數字是重要的。
\documentclass{article}
\usepackage{geometry}
\usepackage{multicol}
\usepackage{tikz} % also for pgfmathparse
\usepackage{pgfmath} % also for pgfmathparse
\usepackage{siunitx} % also for pgfmathparse
\usepgflibrary{fpu}
\pgfkeys{/pgf/fpu}
\pgfkeys{/pgf/fpu/output format=sci}
\pgfkeys{/pgf/number format/.cd, sci, sci e, sci zerofill, precision = 3}
\newcommand{\example}[1]{%
\pgfmathsetseed{#1}%
\pgfmathsetmacro{\FACTOR}{0.90}% constrol the randomness span
\pgfmathrandominteger{\NA}{1}{9}%
\pgfmathsetmacro{\LAA}{2.0*(1 + \FACTOR*rand)}%
#1\quad\Num{\NA}\quad\Num{\LAA}\par
}
\newcommand{\Num}[1]{\pgfmathprintnumberto{#1}{\tmpnum}\ensuremath{\num{\tmpnum}}}
\begin{document}
\begin{multicols}{3}
\count255=0
\loop\ifnum\count255<120
\expandafter\example{\the\count255}
\advance\count255 1
\repeat
\end{multicols}
\end{document}
如果我們查看該表,所有以 開頭的參數呼叫都會1
產生相同的輸出,以及相同的 for2
等等。
另一方面,如果我註解掉與 相關的行fpu
,輸出將變為
隨機整數看起來不那麼隨機,因為只選了 1、4 和 7。
這是我透過expl3
以下方式得到的xfp
:
\documentclass{article}
\usepackage{geometry}
\usepackage{multicol}
\usepackage{siunitx,xfp}
\sisetup{round-precision=5,round-mode=figures,scientific-notation=true}
\newcommand{\FACTOR}{0.9}
\newcommand{\example}[1]{%
\pdfsetrandomseed #1\relax
#1\quad\num{\fpeval{randint(1,9)}}\quad\num{\fpeval{2*(1+\FACTOR*rand())}}\par
}
\begin{document}
\begin{multicols}{3}
\count255=0
\loop\ifnum\count255<120
\expandafter\example{\the\count255}
\advance\count255 1
\repeat
\end{multicols}
\end{document}
答案3
透過使用 @Mark Wibrow 的回复,我不僅能夠改進隨機演算法(透過使用實際上來自第二版 Numerical Recipies 的生成器的新參數),而且還指出與 pgf 的 fpu 不相容以及種子的設定。注意:在我的應用程式中,我需要 fpu 來計算多個量,這些 mwe 不會顯示它。
以下範例顯示,當啟動 /pgf/fpu 時,即使使用改進的參數,隨機數產生器也能如預期運作。如果我在本地停用它,結果會好得多。我不知道如何解決這個問題,但不知何故,函數 pgfmathsetseed 受到影響並且無法產生正確的資料。這是例子
\documentclass{standalone}
\usepackage{tikz,pgfmath,pgffor,siunitx,multicol}
\usepgflibrary{fpu}
\pgfkeys{/pgf/fpu/output format=sci}
\pgfkeys{/pgf/number format/.cd, sci, sci e, sci zerofill, precision = 3}
\pgfkeys{/pgf/fpu=true} % this breaks pgfmathsetseed
\makeatletter
\def\pgfmath@rnd@a{16807}
\def\pgfmath@rnd@r{2836}
\def\pgfmath@rnd@q{127773}
\makeatother
\newcommand{\pgfmathsetseednew}[1]{%
\pgfkeys{/pgf/fpu=false}
\pgfmathsetseed{#1}
\pgfkeys{/pgf/fpu=true}
}
\newcommand{\exampleA}[1]{%
\pgfmathsetseed{#1}%
\pgfmathrandominteger{\r}{1}{9}
\pgfmathsetmacro{\LAA}{2.0*(1 + 0.90*rand)}
#1 \quad \r \quad \Num{\LAA}\par
}
\newcommand{\exampleB}[1]{%
\pgfmathsetseednew{#1}
\pgfmathrandominteger{\r}{1}{9}
\pgfmathsetmacro{\LAA}{2.0*(1 + 0.90*rand)}
#1 \quad \r \quad \Num{\LAA}\par
}
\newcommand{\Num}[1]{\pgfmathprintnumberto{#1}{\tmpnum}\ensuremath{\num{\tmpnum}}}
\begin{document}
\begin{tabular}{m{0.4\textwidth}m{0.4\textwidth}}
/pgf/fpu globally activated & /pgf/fpu locally deactivated\\
\foreach \i in {80,...,99}{\exampleA{\i}}
&
\foreach \i in {80,...,99}{\exampleB{\i}}
\end{tabular}
\end{document}
輸出是
所以,就我而言,我需要在本地停用fpu。
答案4
我更喜歡使用lua
隨機數產生器:
\documentclass[letterpaper,9pt]{article}
\usepackage{tikz} % also for pgfmathparse
\usepackage{pgfmath} % also for pgfmathparse
\usepackage{siunitx} % also for pgfmathparse
\usepackage{luacode,multicol}
\usepgflibrary{fpu}
\pgfkeys{/pgf/fpu}
\pgfkeys{/pgf/fpu/output format=sci}
\pgfkeys{/pgf/number format/.cd, sci, sci e, sci zerofill, precision = 3}
\NewDocumentCommand{\Seed}{O{os.time( )}}{%
\directlua{math.randomseed ( #1 ) ;}%
}
\NewDocumentCommand{\Random}{oom}{%
% no argument : real number between 0 and 1
% upper : integer numbers between 1 and upper (both inclusive).
% lower and upper : integer numbers between lower and upper
% (both inclusive).
\IfNoValueTF{#2}{% not 2 arguments
\IfNoValueTF{#1}{% no arguments
\luadirect{
t = math.random ( ) ;
}
}{%
\luadirect{
t = math.random ( #1 ) ;
}
}
}{%
\luadirect{
t = math.random ( #1 , #2 ) ;
}
}
\bgroup
\edef\foo{\luadirect{tex.print ( t )}}
\global\let#3=\foo
\egroup
}
\newcommand{\example}[1]{%
\pgfmathsetseed{#1}
\pgfmathsetmacro{\FACTOR}{0.90} % constrol the randomness span
% \pgfmathrandominteger{\NA}{1}{9}
\Random[9]{\NA}
\Random{\Rand}
\pgfmathsetmacro{\LAA}{2.0*(1 + \FACTOR*\Rand)}
\begin{tabular}{ccc}
#1 & \Num{\NA} & \Num{\LAA}
\end{tabular}
}
\newcommand{\Num}[1]{\pgfmathprintnumberto{#1}{\tmpnum}\ensuremath{\num{\tmpnum}}}
\begin{document}
\begin{multicols}{3}
\count255=0
\loop\ifnum\count255<120
\expandafter\example{\the\count255}
\advance\count255 1
\repeat
\end{multicols}
\end{document}