我想生成一个简单的宏来生成\x
1 或 -1。但我不确定该怎么做。
我设置了下面的代码,但我相信它会在 -1、0 和 1 之间随机选择。
我必须做哪些调整才能让它仅在 -1 和 1 之间进行选择?
\documentclass{article}
\usepackage{pgf}
\usepackage{pgffor}
\pgfmathsetseed{\number\pdfrandomseed}
\begin{document}
\pgfmathsetmacro{\x}{int(random(-1,1))}
\x
\end{document}
答案1
有一个 PGF 数学函数可以从项目列表中随机选择。这可用于解决一般问题:
\documentclass{article}
\usepackage{pgffor}
\begin{document}
\pgfmathdeclarerandomlist{ones}{{-1}{1}}
\foreach \x in {1,...,10}{
\pgfmathrandomitem{\choice}{ones}
\choice\space
}
\pgfmathdeclarerandomlist{choices}{{1}{0}{-1}{2}{-2}}
\foreach\x in {1,...,10}{
\pgfmathrandomitem{\choice}{choices}
\choice\space
}
\end{document}
答案2
这是一个基于 LuaLaTeX 的解决方案。它以数学模式输出的结果\x
;如果您不需要,只需删除$
定义中使用的两个符号\x
即可。(如果您好奇它是如何工作的:Lua 函数以相等的概率math.random(2)
生成数字1
和2
。乘以math.random(2)
和2
减去3
从而以相等的概率生成数字-1
和1
。)
\documentclass{article}
\newcommand\x{$\directlua{tex.sprint(2*math.random(2)-3)}$}
\begin{document}
\x, \x, \x, \x, \x; \x, \x, \x, \x, \x; \x, \x, \x, \x, \x
\end{document}
你进一步问道,
我如何
\x
从一组固定的任意常数中随机分配一个值?
我将假设这些常量可以是数字或字符串。将上面显示的基于 Lua 的方法概括为处理这种情况很简单。首先,使用指令\luaexec
设置一个 Lua table
(不要与 LaTeX 混淆table
!),其中包含N
常量——基本上是一个 Nx1 逗号分隔的数字和字符串列表;在下面的代码中,N=5
。(字符串常量中可以有 LaTeX 宏。但请注意,必须“转义”反斜杠(\
)字符,即将它们输入为\\
。)其次,设置一个 LaTeX 宏——名为,如前所述——使用调用\x
挑选其中一个条目。N
math.random(N)
\documentclass{article}
\usepackage{luacode} % for "\luaexec" macro
% Define a Lua table that contains N (fairly) arbitrary entries
\luaexec{N = 5 ;
mylist = {5,
"abc",
"DEF",
"$\\Gamma$",
"$\\frac{\\pi^2}{\\int_0^1\\!f(x)\\,dx}$"
} }
% Define a LaTeX macro that selects one of the N entries at random
\newcommand\x{\directlua{tex.sprint(mylist[math.random(N)])}}
\begin{document}
\obeylines % just for this example
\x, \x, \x, \x, \x
\x, \x, \x, \x, \x
\x, \x, \x, \x, \x
\end{document}
答案3
-1
显然,从、0
和中选择1
是由于错误造成的,random
不应与否定参数一起使用,如\pgfmathparse 返回幻像 .0.0
相反,您可以在指定域中使用宏,然后进行移位/缩放。
最简单的也许是
\pgfmathsetmacro{\x}{int(2*random(0,1)-1)}
答案4
目录:
关于随机选择
1
或的初步答案-1
,关于使用包的第一个附录新工具更普遍地在支撑项中进行可扩展选择。有关更有效(如果执行多次)的一般原则,请参阅评论,
仅针对数值情况的第二个附录将使用逗号分隔列表随机选取(再次扩展)xintexpr。
初步答复
无论如何,您都在使用 pdftex 命名的随机相关实用程序 ( \pdfrandomseed
)。最简单(也可能是最快的)就是
\documentclass{article}
%\usepackage{pgf}
%\pgfmathsetseed{\number\pdfrandomseed}% not needed here
\makeatletter
\def\plusorminusone{\ifnum\pdfuniformdeviate\tw@>\z@-\fi 1}
\makeatother
\begin{document}
\plusorminusone
\plusorminusone
\plusorminusone
\plusorminusone
\plusorminusone
\plusorminusone
\plusorminusone
\plusorminusone
\plusorminusone
\plusorminusone
\end{document}
(代码使用了\tw@
, \z@
--- 因此\makeatletter
--- 这个想法很愚蠢,认为它可能比 和 稍快2
,0
而且不必担心留下空格标记来正确终止它们(这里,唯一0
))在某些情况下,您可能更喜欢变体
\ifnum\pdfuniformdeviate\tw@>\z@\expandafter-\fi 1
也许
\the\numexpr\ifnum\pdfuniformdeviate\tw@>\z@-\fi 1\relax
另外,你可能习惯于\pgfmathparse
输入语法,那么也许是这样的
\makeatletter
\def\plusorminusoneset #1{\edef#1{\ifnum\pdfuniformdeviate\tw@>\z@-\fi 1}}
\makeatother
\plusorminusoneset\x
\x
\plusorminusoneset\x
\x
但这看起来使用起来很麻烦。
第一附录
要从(非预定义的)列表中随机选择可扩展的列表,可以使用\xintNthElt
包新工具。
\documentclass{article}
\usepackage{xinttools}
\newcommand\myrandomelement [1]% this comment character isn't needed but pretty
{\xintNthElt{1+\pdfuniformdeviate \xintNthElt{0}{#1}}{#1}}
\begin{document}
\myrandomelement {ABCDEF}, \myrandomelement {ABCDEF}, \myrandomelement
{ABCDEF}, \myrandomelement {ABCDEF}, \myrandomelement {ABCDEF},
\myrandomelement {ABCDEF}, \myrandomelement {ABCDEF}, \myrandomelement
{ABCDEF}, \myrandomelement {ABCDEF}, \myrandomelement {ABCDEF}, \myrandomelement {ABCDEF}, \myrandomelement {ABCDEF}, \myrandomelement {ABCDEF}, \myrandomelement {ABCDEF}, \myrandomelement {ABCDEF}, \myrandomelement {ABCDEF}, \myrandomelement {ABCDEF}, \myrandomelement {ABCDEF}, \myrandomelement {ABCDEF}, \myrandomelement {ABCDEF}
\end{document}
如果需要,请使用括号:\myrandomelement {{ABC}{$1$}{\par}}
。
评论:
代码可扩展
代码每次都会重新计算元素的总数,因此在信息稳定的环境中,最好有一个带有两个参数的宏,其中第二个参数是已知的元素数量,
我们需要移动一位,因为元素从一开始编号,(用于
0
获取元素的数量......)xinttools 有一些内部宏,它们处理逗号分隔的列表,并从零开始计数,而不是从一开始;但它们是私有的……好吧,好吧,让我们公开一下,要使用的宏是
\xintCSVNthEltPy
和\xintCSVLength
。源代码包含以下注释:我们在此不对括号剥离或空格采取任何预防措施。而且宏很短。由于上述原因,它们暂时不会在用户手册中记录,也是为了保留修改界面的可能性,以防 xintexpr 方面的某些发展需要它。尽管如此,也提供了可直接使用的名称。
您仍然可以使用 处理逗号分隔的值
\xintCSVtoList
。列表参数可能是一个宏,它不必像我的例子那样明确。
第二附录
处理数值时,你可以使用xintexpr表達式。
\documentclass{article}
\usepackage{xintexpr}
\begin{document}
\xintdeffloatvar Pi := 3.1415926535897932;
\xintdeffloatvar e := 2.7182818284590452;
\xintthefloatexpr \empty [sqrt(3), Pi, e][\pdfuniformdeviate 3]\relax
\xintthefloatexpr ([sqrt(3), Pi, e][\pdfuniformdeviate 3])\relax
\xintthefloatexpr [4]
subs(seq(([S, Pi, e][\pdfuniformdeviate 3]), i=1..10), S = sqrt(3))\relax
\end{document}
一些评论:
因为可以接受一个可选参数,就像上一个例子中的,这意味着将输出四舍五入为精度位数;用于平静
\empty
(可扩展)解析器,因为括号接下来用于完全不同的东西,\xintthefloatexpr
[4]
4
\empty
在第二个例子中,改用括号,
在第三个例子中,我们想执行十次,但不想重复计算三的平方根十次;因此我们使用替换机制;分隔表达式和赋值变量的逗号不能与之前的逗号混淆。这里
seq
(uence) 构造隐藏了之前的逗号,但是我们需要在列表提取器周围加上括号,因为seq
有一个迭代变量(这里i
),并且之前的逗号i
不能与之前的逗号混淆。我认为也可以使用括号,但这需要在手册中检查。
可以这样对最后一个例子进行编码:
\xintthefloatexpr [4]
subs(seq([L][\pdfuniformdeviate 3], i=1..10), L = sqrt(3), Pi, e)\relax
其优点是不需要额外的括号。