我的目标是定义\avar
和\bvar
使得它们是 1 到 11 之间的整数(包括 1 和 11),但没有共同的因子,并且它们永远不会相等。
我认为我编写的代码应该这样做,但有时却不能,我不知道为什么。
有没有更简单的方法来实现这一点?或者有没有简单的方法来修复我得到的代码?
\documentclass{article}
\usepackage{pgf}
\usepackage{pgffor}
\usepackage{multicol}
\pgfmathsetseed{\number\pdfrandomseed}
\newcommand{\InitVariablesDOS}
{%
% This randomly sets \avar to be a whole number between 1 and 10.
% I am using the list format so that when I'm not doing a MWE,
% I can easily weight, say, 7s to come more often.
% Let's say in our example \avar is randomly set to 6....
\pgfmathdeclarerandomlist{avar}{{1}{2}{3}{4}{5}{6}{7}{8}{9}{10}}
\pgfmathrandomitem{\avar}{avar}
% If \avar=6 I want \bvar to share no common factors (other than 1) with 6.
% So, \bvar is selected from {DOSIfSix},
% which are whole numbers which do not have the factors 2,3, or 6.
\pgfmathdeclarerandomlist{DOSIfOne}{{1}{2}{3}{4}{5}{6}{7}{8}{9}{10}}
\pgfmathdeclarerandomlist{DOSIfTwo}{{1}{3}{5}{7}{9}}
\pgfmathdeclarerandomlist{DOSIfThree}{{1}{2}{4}{5}{7}{8}{10}}
\pgfmathdeclarerandomlist{DOSIfFour}{{1}{3}{5}{7}{9}}
\pgfmathdeclarerandomlist{DOSIfFive}{{1}{2}{3}{4}{6}{7}{8}{9}}
\pgfmathdeclarerandomlist{DOSIfSix}{{1}{5}{7}{11}}
\pgfmathdeclarerandomlist{DOSIfSeven}{{1}{2}{3}{4}{5}{6}{8}{9}{10}}
\pgfmathdeclarerandomlist{DOSIfEight}{{1}{3}{5}{7}{9}}
\pgfmathdeclarerandomlist{DOSIfNine}{{1}{2}{4}{5}{7}{8}{10}}
\pgfmathdeclarerandomlist{DOSIfTen}{{1}{3}{7}{9}{11}}
\ifcase\avar\relax% This should define \bvar so that it shares no common factors with \avar.
\or \pgfmathrandomitem{\bvar}{DOSIfOne}
\or \pgfmathrandomitem{\bvar}{DOSIfTwo}
\or \pgfmathrandomitem{\bvar}{DOSIfThree}
\or \pgfmathrandomitem{\bvar}{DOSIfFour}
\or \pgfmathrandomitem{\bvar}{DOSIfFive}
\or \pgfmathrandomitem{\bvar}{DOSIfSix}
\or \pgfmathrandomitem{\bvar}{DOSIfSeven}
\or \pgfmathrandomitem{\bvar}{DOSIfEight}
\or \pgfmathrandomitem{\bvar}{DOSIfNine}
\or \pgfmathrandomitem{\bvar}{DOSIfTen}
\fi
\xdef\bvar{\bvar}
}
\newcommand{\avarandbvar}
{%
\InitVariablesDOS
\(avar=\avar\)
\(bvar=\bvar\)
\vspace{0.5cm}
}
\newcommand{\manyavarandbvars}[1]{\foreach \x in {1,...,#1} {\avarandbvar}}
\pagestyle{empty}
\begin{document}
\begin{multicols}{5}
\manyavarandbvars{70}
\end{multicols}
\end{document}
答案1
为了进行比较,这里有一个基于 luatex 的解决方案。(我使用 ConTeXt,但将其转换为 LaTeX 也应该很简单)。为了使其更具挑战性,我通过算法生成了列表bvars
。
我不确定为什么有些列表到 10,而其他列表到 11。在下面的代码中,所有列表都到 10。
\startluacode
-- Euclid's algorithm for gcd
local gcd = function(m, n)
while m ~= 0 do
m, n = math.mod(n,m), m
end
return n
end
local avars = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
local bvars = {}
-- Generate bvars
for i = 1, #avars do
local a = avars[i]
if bvars[a] == nil then
local b = {1}
for j = 2, 10 do
if gcd(a, j) == 1 then
b[#b + 1] = j
end
end
bvars[a] = b
end
end
local random, format = math.random, string.format
local sampleAandB = function()
local i = random(#avars)
local a = avars[i]
local j = random(#bvars[a])
local b = bvars[a][j]
return a, b
end
local avarandombvar = function()
local a, b = sampleAandB()
context.dontleavehmode()
context.framed({"frame=off, align=middle"}, format("avar = %s \\crlf bvar = %s", a, b))
context.blank{"big"}
end
interfaces.definecommand ("avarandombvar", {macro = avarandombvar})
\stopluacode
\starttext
\startcolumns[n=5]
\dorecurse{70}{\avarandombvar}
\stopcolumns
\stoptext
这使
答案2
首先解决你的问题:
您需要保留\avar
以防止其发生变化。这可以\edef\avar{\avar}
在之后添加来完成\pgfmathrandomitem{\avar}{avar}
。
建议:您可以将随机列表的声明移到前言中。这样,它们只定义一次,而不是每次都\InitVariablesDOS
使用。并且您应该注释掉几行的行尾\InitVariablesDOS
。否则,它们可能会产生虚假空格,具体取决于调用宏的位置。
\documentclass{article}
\usepackage{pgf}
\usepackage{pgffor}
\usepackage{multicol}
\pgfmathsetseed{\number\pdfrandomseed}
\pgfmathdeclarerandomlist{avar}{{1}{2}{3}{4}{5}{6}{7}{8}{9}{10}}
\pgfmathdeclarerandomlist{DOSIfOne}{{1}{2}{3}{4}{5}{6}{7}{8}{9}{10}}
\pgfmathdeclarerandomlist{DOSIfTwo}{{1}{3}{5}{7}{9}}
\pgfmathdeclarerandomlist{DOSIfThree}{{1}{2}{4}{5}{7}{8}{10}}
\pgfmathdeclarerandomlist{DOSIfFour}{{1}{3}{5}{7}{9}}
\pgfmathdeclarerandomlist{DOSIfFive}{{1}{2}{3}{4}{6}{7}{8}{9}}
\pgfmathdeclarerandomlist{DOSIfSix}{{1}{5}{7}{11}}
\pgfmathdeclarerandomlist{DOSIfSeven}{{1}{2}{3}{4}{5}{6}{8}{9}{10}}
\pgfmathdeclarerandomlist{DOSIfEight}{{1}{3}{5}{7}{9}}
\pgfmathdeclarerandomlist{DOSIfNine}{{1}{2}{4}{5}{7}{8}{10}}
\pgfmathdeclarerandomlist{DOSIfTen}{{1}{3}{7}{9}{11}}
\newcommand{\InitVariablesDOS}
{%
\pgfmathrandomitem{\avar}{avar}%
% added as workaround
\edef\avar{\avar}%
% to show the problem, uncomment the next line and comment out the previous one
% \(avar=\avar\)
\ifcase\avar\relax% This should define \bvar so that it shares no common factors with \avar.
\or \pgfmathrandomitem{\bvar}{DOSIfOne}%
\or \pgfmathrandomitem{\bvar}{DOSIfTwo}%
\or \pgfmathrandomitem{\bvar}{DOSIfThree}%
\or \pgfmathrandomitem{\bvar}{DOSIfFour}%
\or \pgfmathrandomitem{\bvar}{DOSIfFive}%
\or \pgfmathrandomitem{\bvar}{DOSIfSix}%
\or \pgfmathrandomitem{\bvar}{DOSIfSeven}%
\or \pgfmathrandomitem{\bvar}{DOSIfEight}%
\or \pgfmathrandomitem{\bvar}{DOSIfNine}%
\or \pgfmathrandomitem{\bvar}{DOSIfTen}%
\fi
\edef\bvar{\bvar}%
}
\newcommand{\avarandbvar}
{%
\InitVariablesDOS
\(avar=\avar\)
\(bvar=\bvar\)
\vspace{0.5cm}
}
\newcommand{\manyavarandbvars}[1]{\foreach \x in {1,...,#1} {\avarandbvar}}
\pagestyle{empty}
\begin{document}
\begin{multicols}{5}
\manyavarandbvars{70}
\end{multicols}
\end{document}
现在说说问题的原因:
在这种情况下,它与组和/或全局化无关\avar
。问题来自pgf
以及它如何用 定义宏\pgfmathrandomitem
。如果后者被调用用于不同的宏,例如
\pgfmathrandomitem{\avar}{avar}
\pgfmathrandomitem{\bvar}{bvar}
第二次调用也会改变第一次的结果。因此,必须用 保留第一个结果\edef\avar{\avar}
。
详细信息(你可以在这里停止阅读):
该宏的简单定义如下\def
(pgfmathfunctions.random.code.tex,第 241 和 242 行):
\pgfmathrandominteger{\pgfmath@randomtemp}{1}{\pgfmath@randomlistlength}%
\def#1{\csname pgfmath@randomlist@#2@\pgfmath@randomtemp\endcsname}}}
可以看出,宏的内容取决于\pgfmath@randomtemp
。如果它发生变化,宏也会发生变化。每次\pgfmathrandomitem
调用时都会发生这种情况,即使是对来自不同列表的不同宏执行此操作也是如此。
由于我想不出在这里使用\def
而不是 的理由\edef
来避免这个问题,所以我认为这是一个错误。