私は 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 らの Numerical references in C, 2nd edition から収集したものです。代替案も提案されています ( のコメントにも記載されています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 からの返信を使用することで、ランダム アルゴリズム (Numerical Recipies の第 2 版から実際に取得されたジェネレーターの新しいパラメーターを使用することで) を改善することができましたが、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}