5

In the following MWE I use \lhead{\stepcounter{step}\arabic{step}} and it works perfectly, incrementing by 1 each page. I also use \chead{\setrand{100}\arabic{rand}} and get the same number every page. If I call \setrand somewhere on the page, it works. If it is checking the value of rand, why doesn't it check the value of 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}
5

You're using \global where it's not needed and not using it where it's needed!

The header is computed in a group, so \setrand always starts from the beginning and, of course, gives the same result. Use global assignments always.

\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}

enter image description here


In your declarations like \global\newcount\idum, \global is redundant because they are at the outermost level. It doesn't mean that subsequent operations on \idum are global. An assignment such as

\multiply\idum by\ia

is local (unless processed at time when \globaldefs is positive, but this is quite esoteric), so its effect will be undone as soon as the group in which it appears ends. If you want to operate on \idum globally, you have to add \global in front of the assignment, so

\global\multiply\idum by\ia

and similarly for the other assignments.

Note that the elementary operations on LaTeX counters such as your rand are global because \stepcounter{rand} expands to \global\advance\c@rand\@ne.

In general, it's better programming operating on a register always locally or always globally, because local assignments followed by global ones to the same variable use up positions in the stack TeX uses for undoing local assignments.

In this particular case, it's surely better to do operations globally. It might be not necessary in all computations, but some deeper analysis on the algorithm should be done. For instance, if a register is only used for temporary storage, operations on it might as well be local.

  • Interesting. Is there anything else I should know about \global, or constants like \@ne and \zr@? – John Kormylo Nov 21 '13 at 22:44
  • @JohnKormylo \@one and \z@ are commonly used in place of 1 and 0 because they don't give problems with TeX looking for spaces after them. I'll add something about \global. – egreg Nov 21 '13 at 22:48
  • I was just wondering if there were others, like \tw@ ;-) – John Kormylo Nov 22 '13 at 4:21
  • @JohnKormylo There are \z@ (0), \@ne (1), \tw@ (2), \thr@@ (3), \sixt@@n (16), \@xxxii (32), \@cclv (255), \@cclvi (256), \@m (1000), \@M (10000), \@Mi (10001), \@Mii (10002), \@Miii (10003), \@Miv (10004), \@MM (20000). And \active (13). – egreg Nov 22 '13 at 10:11
  • I should mention that additional improvements can be found in my answer to tex.stackexchange.com/questions/144193/… – John Kormylo Nov 23 '13 at 0:41

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.