为什么 fancyhdr 不喜欢随机数?

为什么 fancyhdr 不喜欢随机数?

在以下 MWE 中,我使用 \lhead{\stepcounter{step}\arabic{step}},它运行完美,每页递增 1。我还使用 \chead{\setrand{100}\arabic{rand}},每页都得到相同的数字。如果我在页面上的某个地方调用 \setrand,它就会起作用。如果它正在检查 rand 的值,为什么不检查 step 的值?

\documentclass{article}
\usepackage{fancyhdr}

\makeatletter
% The following is taken from \cite{Numerical Recipes in C}.
% The resulting MAX_RAND = 134456
% Proven good statistics (relatively speaking) but designed for speed.
% Uses 8 entry shuffle.
% Output through counter rand
%
% \randinit required for initialization
% \setrand{n} outputs rand between 0 and (n-1)
% \nextrand uses same scale computed by last \setrand

\newcounter{rand}%scaled random number
\newcounter{index}% used by shuffle

\global\newcount\idum
\global\newcount\im
\global\newcount\ia
\global \newcount\ic
\im = 134456\relax
\ia = 8121\relax
\ic = 28411\relax

\newcount\temp

\def\step@rand{% computes next value for \idum (internal only)
 \multiply\idum by\ia
 \advance\idum by\ic
 \temp = \idum% compute idum mod im
 \divide\temp by\im
 \multiply\temp by\im
 \advance\idum by -\temp
}

\global\newcount\shuffle
\shuffle = 16807\relax
\global\newcount\storeA
\global\newcount\storeB
\global\newcount\storeC
\global\newcount\storeD
\global\newcount\storeE
\global\newcount\storeF
\global\newcount\storeG
\global\newcount\storeH

\def\shuffle@rand{% random shuffle (internal only)
 \step@rand
 \c@index = \idum
 \step@rand
 \divide\c@index by\shuffle
 \advance\c@index by 1
 \c@rand = \csname store\Alph{index}\endcsname
 \csname store\Alph{index}\endcsname = \idum
}

\newcommand{\randinit}{% required to initialize PRNG
 \idum = \day
 \multiply\idum by 1440\relax
 \advance\idum by \time
 \step@rand%warmup
 \step@rand
 \step@rand
 \step@rand
 \storeA = \idum% fill shuffle array
 \step@rand
 \storeB = \idum
 \step@rand
 \storeC = \idum
 \step@rand
 \storeD = \idum
 \step@rand
 \storeE = \idum
 \step@rand
 \storeF = \idum
 \step@rand
 \storeG = \idum
 \step@rand
 \storeH = \idum
}

\global\newcount\scale

\newcommand{\setrand}[1]{% scales rand between 0 and (#1 -1)
 \scale = 1\relax
 \ifnum #1 > 0%check for valid #1
    \scale = \im
    \divide\scale by #1\relax
    \fi
 \shuffle@rand
 \divide\c@rand by\scale
}

\newcommand{\nextrand}{% uses same scale as before
 \shuffle@rand
 \divide\c@rand by\scale
}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\makeatother

\newcounter{step}

\begin{document}
\randinit
\pagestyle{fancyplain}
\lhead{\stepcounter{step}\arabic{step}}
\chead{\setrand{100}\arabic{rand}}

\setrand{100}\arabic{rand}\par
\setrand{100}\arabic{rand}\par
\setrand{100}\arabic{rand}\par
\setrand{100}\arabic{rand}\par
\setrand{100}\arabic{rand}\par
\setrand{100}\arabic{rand}\par

\newpage
This page intentionally left blank.

\newpage
This page intentionally left blank.

\end{document}

答案1

\global您在不需要的地方使用它,而在需要的地方却没有使用它!

标题是按组计算的,因此\setrand总是从头开始,当然,结果也一样。始终使用全局分配。

\documentclass{article}

\usepackage[
  paperheight=6cm,
  paperwidth=10cm,
  margin=.5cm,
  includehead,
  includefoot
]{geometry}

\usepackage{fancyhdr}
\pagestyle{fancy}
\fancyhf{}
\fancyhead[C]{\setrand{100}\arabic{rand}}
\fancyfoot[C]{\thepage}

\makeatletter
% The following is taken from \cite{Numerical Recipes in C}.
% The resulting MAX_RAND = 134456
% Proven good statistics (relatively speaking) but designed for speed.
% Uses 8 entry shuffle.
% Output through counter rand
%
% \randinit required for initialization
% \setrand{n} outputs rand between 0 and (n-1)
% \nextrand uses same scale computed by last \setrand

\newcounter{rand}%scaled random number
\newcounter{index}% used by shuffle

\newcount\idum
\newcount\im
\newcount\ia
\newcount\ic
\im = 134456
\ia = 8121
\ic = 28411

\newcount\temp

\def\step@rand{% computes next value for \idum (internal only)
 \global\multiply\idum by\ia
 \global\advance\idum by\ic
 \global\temp = \idum% compute idum mod im
 \global\divide\temp by\im
 \global\multiply\temp by\im
 \global\advance\idum by -\temp
}

\newcount\shuffle
\shuffle = 16807
\newcount\storeA
\newcount\storeB
\newcount\storeC
\newcount\storeD
\newcount\storeE
\newcount\storeF
\newcount\storeG
\newcount\storeH

\def\shuffle@rand{% random shuffle (internal only)
 \step@rand
 \c@index = \idum
 \step@rand
 \global\divide\c@index by\shuffle
 \global\advance\c@index by \@ne
 \global\c@rand = \csname store\Alph{index}\endcsname
 \global\csname store\Alph{index}\endcsname = \idum
}

\newcommand{\randinit}{% required to initialize PRNG
 \global\idum = \day
 \global\multiply\idum by 1440
 \global\advance\idum by \time
 \global\step@rand%warmup
 \step@rand
 \step@rand
 \step@rand
 \global\storeA = \idum% fill shuffle array
 \step@rand
 \global\storeB = \idum
 \step@rand
 \global\storeC = \idum
 \step@rand
 \global\storeD = \idum
 \step@rand
 \global\storeE = \idum
 \step@rand
 \global\storeF = \idum
 \step@rand
 \global\storeG = \idum
 \step@rand
 \global\storeH = \idum
}

\newcount\scale

\newcommand{\setrand}[1]{% scales rand between 0 and (#1 -1)
 \global\scale = \@ne
 \ifnum #1 > \z@ %check for valid #1
   \global\scale = \im
   \global\divide\scale by #1\relax
 \fi
 \shuffle@rand
 \divide\c@rand by\scale
}

\newcommand{\nextrand}{% uses same scale as before
 \shuffle@rand
 \global\divide\c@rand by\scale
}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\makeatother

\begin{document}
\randinit

\setrand{100}\arabic{rand}
\setrand{100}\arabic{rand}
\setrand{100}\arabic{rand}
\setrand{100}\arabic{rand}
\setrand{100}\arabic{rand}
\setrand{100}\arabic{rand}
\setrand{100}\arabic{rand}

\newpage

This page intentionally left blank.
\newpage

This page intentionally left blank.
\end{document}

在此处输入图片描述


在诸如 之类的声明中\global\newcount\idum\global它们是多余的,因为它们位于最外层。它没有意味着后续操作\idum是全局的。诸如

\multiply\idum by\ia

是局部的(除非在为正时进行处理\globaldefs,但这是相当深奥的),因此一旦它出现的组结束,其效果就会被取消。如果你想在\idum全球范围内进行操作,你\global在作业前面添加,所以

\global\multiply\idum by\ia

其他作业也同样如此。

请注意,LaTeX 计数器上的基本操作(例如)rand是全局的,因为\stepcounter{rand}扩展为\global\advance\c@rand\@ne

一般来说,总是在本地或总是在全局对寄存器进行编程操作是更好的选择,因为对同一个变量进行本地赋值后再进行全局赋值会耗尽 TeX 用于撤消本地赋值的堆栈中的位置。

在这种特殊情况下,最好全局执行操作。这可能不是所有计算都需要的,但应该对算法进行更深入的分析。例如,如果寄存器仅用于临时存储,则对它的操作最好是本地的。

相关内容