我正在使用 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 语言数值参考》第 2 版中收集的。建议使用替代方案(也列在 的评论中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
产生相同的输出,并且相同的输出2
等等。
另一方面,如果我注释掉与 相关的行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 的回复,我既能够改进随机算法(通过使用实际上来自《数值算法》第二版的生成器的新参数),又能够指出与 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}