提示:我用它bigintcalc.sty
来表示巨大的数字;并pgfmath
定义变量(也许还有其他计算)。
我希望结果为宏,像\Prod{3}
,这样我就可以做进一步的计算;例如\Prod{3}+1
。
\bigintcalc
但是,如果我将 \Prod{3} 放在另一个中,例如\bigintcalcAdd{1}{\Prod{3}}
,这可能不起作用。
我需要做什么?
\documentclass[]{article}
\usepackage{amsmath}
\usepackage{tikz}
\usetikzlibrary{math}% for numbered Variables \x{1}, \x{2}, ....
\usepackage{bigintcalc}% for big numbers (e.g. 9^66)
\begin{document}
\section*{Define Variables}
\tikzmath{
int \i;
\i=0;
for \xValue in {2, 3, 7, 42, 1806}{%
\i=\numexpr\i+1\relax;
\x{\i}=\xValue;
};% %%
}
x(1)= \x{1}, ~~~ x(2)= \x{2}, ~~~ x(3)= \x{3}, ~~~ x(4)= \x{4}, ~~~ x(5)= \x{5}
\section*{bigintcalc-Product as command -- works}
\newcommand\Prod[1]{%
\def\N{#1}%
\def\p{1}%
\foreach \k in {1,...,\N}{%%
\xdef\p{\bigintcalcMul{\p}{\x{\k}}}%
}%%
\p}%
$\text{Prod(3)} = \Prod{3}
= x(1) \times x(2) \times x(3) = 2 \times 3 \times 7$
\section*{Using the result for other calculations-- works not}
\text{Prod(3)} + 1 = %\bigintcalcAdd{1}{\Prod{3}}
\end{document}
答案1
您的宏\Prod
被定义为将结果存储在宏中\p
。因此,的结果\Prod
可以在其他计算中访问,如下所示\p
。
或者,您可以定义一个完全可扩展的宏机制
\MyProd{⟨array-macro⟩}{⟨lowest array index⟩}{⟨highest array index⟩}
,通过触发两个扩展步骤来提供计算结果。扩展可以通过\expanded{..}
/完成\expanded{\unexpanded{..}..}
,但对于以下示例,我决定使用它\romannumeral
来触发扩展。
\documentclass[]{article}
\usepackage{amsmath}
\usepackage{tikz}
\usetikzlibrary{math}% for numbered Variables \x{1}, \x{2}, ....
\usepackage{bigintcalc}% for big numbers (e.g. 9^66)
\newcommand\Prod[1]{%
\def\p{1}%
\foreach \k in {1,...,#1}{%
\xdef\p{\bigintcalcMul{\p}{\x{\k}}}%
}%
\p
}%
\makeatletter
\newcommand\PassFirstToSecond[2]{#2{#1}}%
\@ifdefinable\stopromannumeral{\chardef\stopromannumeral`\^^00 }%
\newcommand\MyProd[3]{%
% #1 - array-macro; #2 - lowest array index; #3 - highest array index;
\romannumeral
\expandafter\MyProdLoop
\expandafter{\the\numexpr(#3)\relax}{#1}{1}{#2}{}%
}%
\newcommand\MyProdLoop[5]{%
% #1 - highest array index; #2 - array-macro; #3 - 1 or empty ;
% #4 - current array index; #5 - result currently calculated so far;
\ifnum\numexpr(#4)\relax>\numexpr(#1)\relax
\expandafter\@secondoftwo\else\expandafter\@firstoftwo\fi
{%
% manual of bigintcalc says: "The macros are fully expandable,
% exactly two expansion steps generate the result."
\expandafter\expandafter\expandafter\PassFirstToSecond
\expandafter\expandafter\expandafter{%
\bigintcalcMul{#3#5}{#2{#4}}%
}{%
\expandafter\PassFirstToSecond\expandafter{%
\the\numexpr(#4)+1\relax
}{%
\MyProdLoop{#1}{#2}{}%
}%
}%
}{\stopromannumeral#5}%
}
\makeatother
\begin{document}
\section*{Define Variables}
\tikzmath{%
int \i;
\i=0;
for \xValue in {2, 3, 7, 42, 1806}{%
\i=\numexpr\i+1\relax;
\x{\i}=\xValue;
};%
}%
\(x(1) = \x{1}\), \hfill
\(x(2) = \x{2}\), \hfill
\(x(3) = \x{3}\), \hfill
\(x(4) = \x{4}\), \hfill
\(x(5) = \x{5}\)%
\section*{bigintcalc-Product as command -- works}
\(\text{Prod(3)} = \Prod{3} = \p = x(1) \times x(2) \times x(3) = 2 \times 3 \times 7\)
\section*{Using the result stored as \texttt{\string\p} for other calculations}
% The result of \Prod{3} is in \p, so use \p:
\(\text{Prod(3)} + 1 = \bigintcalcAdd{1}{\p}\)
\section*{Expandably calculating the result within other calculations by means of \texttt{\string\MyProd}}
% Use the expandable variant:
\(\text{Prod(3)} + 1 = \bigintcalcAdd{1}{\MyProd{\x}{1}{3}}\)
\end{document}
如果使用了 TeX 引擎并且\unexpanded
和\expanded
可用,则可以定义\MyProd
,例如,如下所示:
\makeatletter
\newcommand\MyProd[3]{%
% #1 - array-macro; #2 - lowest array index; #3 - highest array index;
\expanded{\expandafter\MyProdLoop\expandafter{\the\numexpr(#3)\relax}{#1}{1}{#2}{}}%
}%
\newcommand\MyProdLoop[5]{%
% #1 - highest array index; #2 - array-macro; #3 - 1 or empty ;
% #4 - current array index; #5 - result currently calculated so far;
\ifnum\numexpr(#4)\relax>\numexpr(#1)\relax
\expandafter\@secondoftwo\else\expandafter\@firstoftwo\fi
{%
\expanded{%
\unexpanded{\MyProdLoop{#1}{#2}}{}{\the\numexpr(#4)+1\relax}{\bigintcalcMul{#3#5}{#2{#4}}}%
}%
}{\unexpanded{#5}}%
}
\makeatother
如果你足够大胆
- 均需使用足够新的 LaTeX 发行版来配合 l3kernel 软件包 [2021-05-07] 或更高版本
\clist_map_tokens:nn
, - 并相信 l3kernel 内部实现
\clist_map_tokens:nn
不会很快改变,
然后,您可以实现一个可扩展的宏\ArrayElementProduct
,其中恰好两个扩展步骤生成结果,该结果作为其参数,采用数组宏标记和以逗号分隔的数组索引列表,并通过迭代逗号列表,对每个逗号列表项应用一个宏,该宏将索引号由逗号列表项表示的数组元素与迄今为止收集的结果相乘,从而通过在每次迭代中挂接到内部映射中断\clist_map_tokens:nn
来维护迄今为止收集的结果:\clist_map_tokens:nn
\documentclass[]{article}
\usepackage{amsmath}
\usepackage{tikz}
\usetikzlibrary{math}% for numbered Variables \x{1}, \x{2}, ....
\usepackage{bigintcalc}% for big numbers (e.g. 9^66)
\ExplSyntaxOn
\cs_new:Npn \ArrayElementProduct #1#2 {
\exp:w
\exp_last_unbraced:No
\MyStuff_arrayelementproduct_hook_in_clist_mapbreak_initial:wn
{
\clist_map_tokens:nn {#2}{ \MyStuff_arrayelementproduct_hook_in_clist_mapbreak:nnwn{#1} }
}
}
\cs_new:Npn \MyStuff_arrayelementproduct_hook_in_clist_mapbreak_initial:wn #1 \prg_break_point:Nn \clist_map_break: #2 {
#1 \prg_break_point:Nn \clist_map_break: { \exp_end: }
}
\cs_new:Npn \MyStuff_arrayelementproduct_hook_in_clist_mapbreak:nnwn #1#2#3 \prg_break_point:Nn \clist_map_break: #4 {
\exp_args:Nne \use:n { #3 \prg_break_point:Nn \clist_map_break:} {
\tl_if_empty:oTF{\use_none:n #4} {
\exp_not:n {\exp_end:} \bigintcalcMul{1}
}{
\exp_not:n {\exp_end:} \bigintcalcMul{\use_none:n #4}
}{#1{#2}}
}
}
\ExplSyntaxOff
\begin{document}
\section*{Define Variables}
\tikzmath{%
int \i;
\i=0;
for \xValue in {2, 3, 7, 42, 1806}{%
\i=\numexpr\i+1\relax;
\x{\i}=\xValue;
};%
}%
\(x(1) = \x{1}\), \hfill
\(x(2) = \x{2}\), \hfill
\(x(3) = \x{3}\), \hfill
\(x(4) = \x{4}\), \hfill
\(x(5) = \x{5}\)%
\section*{Multiply Variables}
\(x(1) \times x(3) \times x(5) = \x{1} \times \x{3} \times \x{5} = \ArrayElementProduct{\x}{1, 3 , 5}\)
\section*{Test edge cases of input}
\verb*|(\ArrayElementProduct{\x}{1, 3 ,,, , 5})|: (\ArrayElementProduct{\x}{1, 3 ,,, , 5})
\noindent
\verb*|(\ArrayElementProduct{\x}{4})|: (\ArrayElementProduct{\x}{4})
\noindent
\verb*|(\ArrayElementProduct{\x}{, ,,, , })|: (\ArrayElementProduct{\x}{, ,,, , })
\noindent
\verb*|(\ArrayElementProduct{\x}{,})|: (\ArrayElementProduct{\x}{,})
\noindent
\verb*|(\ArrayElementProduct{\x}{})|: (\ArrayElementProduct{\x}{})
\noindent
\verb*|(\ArrayElementProduct{\x}{ })|: (\ArrayElementProduct{\x}{ })
\end{document}
(我想知道我是否忽略了这种事情的官方界面。)