下面的代码是错误的,但它说明了我想要实现的目标。你会如何编写 g 命令?
\usepackage{xfp}
\newcommand{\f}[1]{
\inteval{(#1 - \a) / (\b - \a)}
}
\newcommand{\g}[1]{
f=\f{#1}
if (f>h1)
f = f-(h1-l1)
if (f>h2)
f = f-(h2-l2)
f % meaning return f. My purpose is to return an integer not to type anything.
}
理想情况下,我会有一个 (l_i,h_i) 夫妇列表,其中 h_i>l_i,并且我会从 f 中删除所有 (h_i-l_i) ,其 h_i < f。
如果我只有几个,我可以手动编写它们。否则,我很乐意迭代列表或其他结构。
请建议尽可能简单的语法。这就是我欣赏 xfp 的原因。除了 \inteval 和 \fpeval 之外,其余的都是数学,就像我会写的那样。对于 Latex 新手来说,添加太多东西令人沮丧。
答案1
与其他编程语言不同,TeX 没有“返回值”的概念,因此编程通常要棘手得多(当然,也并非不可能)。
TeX 大致通过扩展和赋值来工作,在这里你可以使用其中任何一种。这里有一个通过扩展工作的版本(这意味着你可以将其用作\g
其他函数或整数表达式的参数):
\newcommand{\f}[1]{%
\inteval{(#1 - \a) / (\b - \a)}}
\newcommand{\g}[1]{%
\expandafter\gaux\expandafter{\number\f{#1}}}
\newcommand{\gaux}[1]{%
\ifnum#1>\hI
\inteval{#1-(\hI-\lI)}%
\else\ifnum #1>\hII
\inteval{#1-(\hII-\lII)}%
\fi\fi}
此处命令使用\g
强制扩展,并将结果传递给。 然后使用 执行条件并返回 中的表达式。我使用而不是 ,因为您(通常)不能在命令名称中使用数字,其他变量也是如此。\f{#1}
\number
\gaux
\gaux
\ifnum
\inteval
\hI
h1
这里有一个使用赋值的可能性。这意味着结果在中返回\freturn
(您可以使用 编写结果\the\freturn
),并且不能嵌套\g
在\g
其自身或其他类似命令中:
\newcommand{\f}[1]{%
\inteval{(#1 - \a) / (\b - \a)}}
\newcount\freturn
\newcommand{\g}[1]{%
\freturn=\f{#1}
\ifnum\freturn>\hI
\freturn=\inteval{\freturn-(\hI-\lI)}
\else\ifnum \freturn>\hII
\freturn=\inteval{\freturn-(\hII-\lII)}
\fi\fi}
这首先将 的输出存储\f{#1}
在 中\freturn
,然后用于\freturn
计算条件,最后\freturn
再次将输出存储在 中。请注意,在这种情况下\g
,它本身不会将任何内容写入输出,您必须写入\g{<num>} \the\freturn
。
答案2
感谢您的帮助。
我整合了你的建议来得到这个工作示例:
\documentclass{article}
\def\maxX{100}
\def\fd{0}
\def\ld{100}
\def\lI{0}
\def\hI{10}
\def\lII{20}
\def\hII{30}
\usepackage{xfp}
\newcommand{\f}[1]{%
\inteval{\maxX * (#1 - \fd) / (\ld - \fd)}
}
\newcount\xTemp
\newcommand{\g}[1]{%
\expandafter\gaux\expandafter{\number\f{#1}}}
\newcommand{\gaux}[1]{%
\xTemp=#1
\ifnum#1>\inteval{\hI}
\xTemp=\inteval{\xTemp-(\hI-\lI)}%
\fi
\ifnum #1>\inteval{\hII}
\xTemp=\inteval{\xTemp-(\hII-\lII)}%
\fi
}
\begin{document}
% below is just a way for me to see the results
\begin{tabular}{ r r }
$x$ & $g(x)$ \\
\hline
0 & \g{0} \the\xTemp\\
15 & \g{15} \the\xTemp\\
35 & \g{35} \the\xTemp\\
\hline
\end{tabular}
\end{document}
我现在将寻找一种方法来迭代这些(l_i,h_i)以重复相同的计算几次,而不必将它们全部写出来。
再次感谢你。
答案3
如果我正确理解了您的目标,那么您有一个子区间列表,并且您想使用所有子区间进行显示的计算。
\documentclass{article}
\ExplSyntaxOn
\int_const:Nn \c_filippo_a_int { 0 } % fd
\int_const:Nn \c_filippo_b_int { 100 } % ld
\int_const:Nn \c_filippo_m_int { 100 } % maxX
\int_new:N \l__filippo_step_int
\seq_const_from_clist:Nn \c_filippo_l_seq { 0,20,40,60,80 } % l_i
\seq_const_from_clist:Nn \c_filippo_h_seq { 10,30,50,70,90 } % h_i
\cs_new:Nn \filippo_f:n
{
\int_eval:n
{
100 * ( #1 - \c_filippo_a_int ) / ( \c_filippo_b_int - \c_filippo_a_int )
}
}
\cs_generate_variant:Nn \filippo_f:n { e }
\cs_new:Nn \filippo_g:n
{
\__filippo_g:ee { \filippo_f:n { #1 } } { 0 }
}
\cs_new:Nn \__filippo_g:nn
{
\int_compare:nTF { #2 < \seq_count:N \c_filippo_l_seq }
{% do the comparison
\int_compare:nTF { #1 > \seq_item:Nn \c_filippo_h_seq { #2 + 1 } }
{
\__filippo_g:ee
{
\int_eval:n
{
#1 -
\seq_item:Nn \c_filippo_h_seq { #2 + 1 } +
\seq_item:Nn \c_filippo_l_seq { #2 + 1 }
}
}
{ \int_eval:n { #2 + 1 } }
}
{
\__filippo_g:ee { #1 } { \int_eval:n { #2 + 1 } }
}
}
{% we've ended the recursion, return the value
#1
}
}
\cs_generate_variant:Nn \__filippo_g:nn { ee }
\NewExpandableDocumentCommand{\g}{m}
{
\filippo_g:n { #1 }
}
\ExplSyntaxOff
\begin{document}
\begin{tabular}{ r r }
$x$ & $g(x)$ \\
\hline
0 & \g{0} \\
1 & \g{1} \\
10 & \g{10} \\
12 & \g{12} \\
15 & \g{15} \\
35 & \g{35} \\
\hline
\end{tabular}
\bigskip
\edef\test{\g{35}}
\texttt{\meaning\test}
\end{document}
该命令\g
是完全可扩展的,如最后一行所示。
的第二个参数\__filippo_g:ee
是递归的循环索引。该函数在新的输入上调用自身,直到子间隔列表完成,此时返回第一个参数,否则循环索引将递增。