灵感来自这个答案我想使用一些随机数生成一个多位加数。
我可以生成随机数,但无法正确使用它们(超出 Tex 容量)。这是我的 MWE:
\documentclass{article}
\usepackage{stringstrings,stackengine}
\newcounter{mysum}
\newcommand\showsum[1]{%
\convertchar[q]{#1}{ }{+}%
\setcounter{mysum}{\numexpr\thestring\relax}%
\def\stackalignment{r}%
\if T\showsums\edef\tmp{\themysum}\else\edef\tmp{~}\fi%
\raisebox{-\dp\strutbox}{+\,}{\stackunder{\underline{\ \Longstack{#1}}}{%
\tmp}}%
}
\usepackage{lcg}
\begin{document}
\reinitrand[first=0, last=1000]
%get three random values:
\newcommand{\random}{\rand\arabic{rand} \rand\arabic{rand} \rand\arabic{rand}}
These are three random values: \random
\def\showsums{T}
\showsum{411 319 217} $\qquad$ %<-- works :-)
\showsum{\random} %<-- doesn't work :-(
\end{document}
答案1
正如@StevenB.Segletes 所说,\rand
是不可扩展的,因此不能仅使用此函数在宏中记录生成的随机数。出于同样的原因,即使我们\showsum
试图递归扩展\random
,也无法从中获得任何有用的东西——如果您直接将参数 传递给它,情况也不会更好\rand\arabic{rand} \rand\arabic{rand} \rand\arabic{rand}
,因为 距离 只有一个扩展步骤\random
。
为了解决这个问题,我建议使用\int_rand:nn
中的函数expl3
,它确实以可扩展的方式生成随机整数(作为参数提供的边界都包含在可能的结果中)。此外,我将把它包装起来,例如,调用 会\myrandsums{5}{1000}{9999}
打印五个随机整数的总和n其中 1000 ≤ n ≤ 9999.
\documentclass{article}
% 'geometry' is only used so that the examples nicely fit on a single line.
\usepackage[hmargin=2cm]{geometry}
\usepackage{stringstrings}
\usepackage{stackengine}
\usepackage{xparse}
\ExplSyntaxOn
\cs_new_protected:Npn \latexfan_showsum:n #1
{
\showsum {#1}
}
\cs_generate_variant:Nn \latexfan_showsum:n { x }
\cs_generate_variant:Nn \seq_use:Nn { NV }
\NewDocumentCommand \myrandsums { m m m }
{
\seq_clear:N \l_tmpa_seq
\int_step_inline:nn {#1}
{ \seq_put_right:Nx \l_tmpa_seq { \int_rand:nn {#2} {#3} } }
\latexfan_showsum:x { \seq_use:NV \l_tmpa_seq \c_space_tl }
}
\ExplSyntaxOff
% Equivalent to the desired \random macro from your example
\newcommand{\hardcodedSumOfThree}{\myrandsums{3}{0}{1000}}
\newcounter{mysum}
\newcommand\showsum[1]{%
\convertchar[q]{#1}{ }{+}%
\setcounter{mysum}{\numexpr\thestring\relax}%
\def\stackalignment{r}%
\if T\showsums\edef\tmp{\themysum}\else\edef\tmp{~}\fi%
\raisebox{-\dp\strutbox}{+\,}{\stackunder{\underline{\ \Longstack{#1}}}{%
\tmp}}%
}
\begin{document}
\def\showsums{T}% Print the result
\showsum{411 319 217}%
%
\qquad
\myrandsums{3}{0}{1000}%
%
\qquad
\hardcodedSumOfThree % ditto
%
\qquad
\myrandsums{5}{1000}{9999}%
%
\qquad
\def\showsums{F}% Don't print the result
\myrandsums{8}{1000}{9999}%
\end{document}
示例输出:
以下是一个稍微复杂一些的变体。它提供了一个\myrandsums
与上面行为相同的函数,此外还\myRandsums
忽略了的当前内容\showsums
:
\myRandsums*{<num>}{<min>}{<max>}
总是打印随机选择的整数的总和;\myRandsums{<num>}{<min>}{<max>}
从不打印结果,仅打印操作数。
\documentclass{article}
% 'geometry' is only used so that the first series of examples nicely fits on a
% single line.
\usepackage[hmargin=2cm]{geometry}
\usepackage{stringstrings}
\usepackage{stackengine}
\usepackage{xparse}
\ExplSyntaxOn
\cs_new_protected:Npn \latexfan_showsum:n #1
{
\showsum {#1}
}
\cs_generate_variant:Nn \latexfan_showsum:n { x }
\cs_generate_variant:Nn \seq_use:Nn { NV }
\cs_new_protected:Npn \latexfan_randsums:nnn #1#2#3
{
\seq_clear:N \l_tmpa_seq
\int_step_inline:nn {#1}
{ \seq_put_right:Nx \l_tmpa_seq { \int_rand:nn {#2} {#3} } }
\latexfan_showsum:x { \seq_use:NV \l_tmpa_seq \c_space_tl }
}
\NewDocumentCommand \myrandsums { m m m }
{
\latexfan_randsums:nnn {#1} {#2} {#3}
}
\NewDocumentCommand \myRandsums { s m m m }
{
\group_begin:
\cs_set:Npx \showsums { \IfBooleanTF {#1} {T} {F} }
\latexfan_randsums:nnn {#2} {#3} {#4}
\group_end:
}
\ExplSyntaxOff
% Equivalent to the desired \random macro from your example
\newcommand{\hardcodedSumOfThree}{\myrandsums{3}{0}{1000}}
\newcounter{mysum}
\newcommand\showsum[1]{%
\convertchar[q]{#1}{ }{+}%
\setcounter{mysum}{\numexpr\thestring\relax}%
\def\stackalignment{r}%
\if T\showsums\edef\tmp{\themysum}\else\edef\tmp{~}\fi%
\raisebox{-\dp\strutbox}{+\,}{\stackunder{\underline{\ \Longstack{#1}}}{%
\tmp}}%
}
\begin{document}
\def\showsums{T}%
\showsum{411 319 217}% Print the result
%
\qquad
\myrandsums{3}{0}{1000}%
%
\qquad
\hardcodedSumOfThree % ditto
%
\qquad
\myrandsums{5}{1000}{9999}%
%
\qquad
\def\showsums{F}% Don't print the result
\myrandsums{8}{1000}{9999}%
\bigskip
\qquad
\myRandsums*{3}{100}{999}%
\qquad
\myRandsums{2}{10}{99}%
\qquad
\myRandsums*{2}{10}{99}%
\qquad
\myRandsums{3}{100}{999}%
\end{document}
示例输出:
答案2
expl3
与 frougon 略有不同的实现,不需要额外的包。
\documentclass{article}
\usepackage{xparse}
\ExplSyntaxOn
\NewDocumentCommand{\randomsum}{smmm}
{% #1 = * to show, #2 = summands, #3 = lower bound, #4 = upper bound
\IfBooleanTF{#1}
{
\bool_set_false:N \l__latexfan_randomsum_solution_bool
}
{
\bool_set_true:N \l__latexfan_randomsum_solution_bool
}
\latexfan_randomsum:nnn { #2 } { #3 } { #4 }
}
\bool_new:N \l__latexfan_randomsum_solution_bool
\seq_new:N \l__latexfan_randomsum_summands_seq
\cs_new_protected:Nn \latexfan_randomsum:nnn
{
\seq_clear:N \l__latexfan_randomsum_summands_seq
% make a sequence with random numbers
\int_step_inline:nn { #1 }
{
\seq_put_right:Nx \l__latexfan_randomsum_summands_seq { \int_rand:nn { #2 } { #3 } }
}
% print the summands, first a raised +
\raisebox{0.51\normalbaselineskip}{$+$}\,
% the summands in column, with a rule in the middle
\begin{tabular}[b]{@{\,}r@{}}
\seq_use:Nn \l__latexfan_randomsum_summands_seq { \\ } \\
\hline
\bool_if:NTF \l__latexfan_randomsum_solution_bool
{% a phantom of the sum to hint at the number of digits
\phantom { \int_eval:n { \seq_use:Nn \l__latexfan_randomsum_summands_seq { + } } }
}
{% the sum
\int_eval:n { \seq_use:Nn \l__latexfan_randomsum_summands_seq { + } }
}
\end{tabular}
}
\ExplSyntaxOff
\begin{document}
\randomsum*{2}{10}{90}\qquad
\randomsum{4}{100}{999}\qquad
\randomsum{7}{1000}{9999}\qquad
\randomsum*{7}{1000}{9999}
\end{document}