代码就这样了,剩下的该怎么完成呢?

\documentclass{article}

\begin{document}

\ExplSyntaxOn

\NewDocumentCommand{\average}{m}{%
}

\ExplSyntaxOff

\average{1,3.7,5} % would return 3.233

\average{1,3.7,5,3.2*2,7.9} % would return 4.8.  the argument number is arbitrary but limited

\end{document}

0


5 个回答
5

要创建一个 expl3 命令来计算几个数字的平均值,包括像 3.2*2 这样的表达式,您可以使用以下代码:

\documentclass{article}

\begin{document}

\ExplSyntaxOn

\NewDocumentCommand{\average}{m}{%
  \average_numbers:n {#1}
}

\cs_new_protected:Nn \average_numbers:n {
  % Parse the argument into a sequence
  \seq_set_from_clist:Nn \l__average_numbers_seq { #1 }
  % Initialize sum and count variables
  \fp_zero_new:N \l__average_sum_fp
  \int_zero_new:N \l__average_count_int
  % Iterate over the sequence
  \seq_map_inline:Nn \l__average_numbers_seq {
    % Increase the count
    \int_incr:N \l__average_count_int
    % Evaluate the expression and add to sum
    \fp_add:Nn \l__average_sum_fp { \fp_eval:n { ##1 } }
  }
  % Compute the average
  \fp_div:Nn \l__average_sum_fp { \int_use:N \l__average_count_int }
  % Output the average
  \fp_use:N \l__average_sum_fp
}

\ExplSyntaxOff

\average{1,3.7,5} % returns 3.233333333333333

\average{1,3.7,5,3.2*2,7.9} % returns 4.8

\end{document}

此代码定义了一个新命令 \average,该命令接受以逗号分隔的数字或表达式列表。它计算已求值的表达式的总和,计算项目数,并通过将总和除以计数来计算平均值。然后使用 \fp_use:N 打印结果

这有帮助吗?:)

1

  • 1
    这似乎无法编译。


    – 

下面定义了\average宏的完全可扩展变体。我还添加了一个可选参数来提供舍入精度。

您不需要任何其他东西来访问变量,无论它们定义为宏还是fp变量。

\documentclass{article}

\ExplSyntaxOn
\cs_new:Npn \xcn_mean:n #1
  { \fp_eval:n { ( \clist_use:nn {#1} { + } ) / \clist_count:n {#1} } }
\NewExpandableDocumentCommand \average { o m }
  {
    \IfNoValueTF {#1}
      { \xcn_mean:n {#2} }
      { \fp_eval:n { round ( \xcn_mean:n {#2}, #1 ) } }
  }
\fp_new_variable:n { aaa }
\fp_set_variable:nn { aaa } { 3.7 }
\ExplSyntaxOff

\begin{document}
\average[3]{1,aaa,5} % would return 3.233

\average{1,3.7,5,3.2*2,7.9} % would return 4.8.  the argument number is arbitrary but limited
\end{document}

扩展变体还允许计算函数返回值的平均值。我使用expkv-cs将可选参数拆分为具有两个键round和的 key=value 参数f。键定义列表中的符号与中的键和其他相关包中的符号V:~相同(请注意,只能在中使用,在该范围之外应该是)。\exp_args:NVexpkv~\ExplSyntaxOnV:

\documentclass{article}

\usepackage{expkv-cs}

\ExplSyntaxOn
\cs_new:Npn \xcn_mean:n #1
  { \fp_eval:n { ( \clist_use:nn {#1} { + } ) / \clist_count:n {#1} } }
\cs_new:Npn \xcn_mean_function:nn #1#2
  {
    \fp_eval:n
      {
        ( \clist_map_tokens:nn {#2} { \__xcn_mean_function_aux:nn {#1} } )
        / \clist_count:n {#2}
      }
  }
\cs_new:Npn \__xcn_mean_function_aux:nn #1#2 { +(#1(#2)) }

\NewExpandableDocumentCommand \average { O{} m }
  { \__xcn_average:nn {#1} {#2} }
\ekvcSplitAndForward \__xcn_average:nn \__xcn_average_aux:nnn
  {
     V:~ round = \c_novalue_tl
    ,V:~ f = \c_novalue_tl
  }
\cs_new:Npn \__xcn_average_aux:nnn #1#2#3
  {
    % #1: round
    % #2: f
    % #3: clist
    \tl_if_novalue:nTF {#1}
      { \__xcn_average_aux:nn {#2} {#3} }
      { \fp_eval:n { round ( \__xcn_average_aux:nn {#2} {#3}, #1 ) } }
  }
\cs_new:Npn \__xcn_average_aux:nn #1#2
  {
    \tl_if_novalue:nTF {#1}
      { \xcn_mean:n {#2} }
      { \xcn_mean_function:nn {#1} {#2} }
  }

\fp_new_variable:n { aaa }
\fp_set_variable:nn { aaa } { 3.7 }
\fp_new_function:n { sq }
\fp_set_function:nnn { sq } { x } { x**2 }
\ExplSyntaxOff

\begin{document}
\average[round=3]{1,aaa,5} % would return 3.233

\average{1,3.7,5,3.2*2,7.9} % would return 4.8.  the argument number is arbitrary but limited

\average[f=sq]{1, 2, 3, 4} % 30/4 = 7.5
\end{document}

4

  • 是否可以访问 \average 中的每个项目并制作一个使用循环逐个添加项目的程序?


    – 

  • @XCN 你为什么要这样做?我看不出有什么好处,\clist_use:nn {#1} { + }代码非常简单简洁。当然可以手动循环,正如我所说,我只是看不出这样做的理由。


    – 

  • 如果我需要一个函数并且已知变量存储在列表中,那么它需要访问该项目。


    – 

  • @XCN 仅对于变量来说你不需要这样做,但是如果你想要依次获得应用于每个项目的函数的平均值,那么你是对的。请参阅我的最新编辑,其中增加了这种可能性。


    – 

可以使用和\average在 OpTeX 中创建可扩展宏\expr\foreach

\optdef\average[3]#1{\immediateassignment\tmpnum=0
   \expr[\the\opt]{(0\foreach#1,\do##1,{+(##1)\incrtmpnum})/\the\tmpnum}}
\def\incrtmpnum{\immediateassignment\advance\tmpnum by1 }

\average{1,3.7,5} % would return 3.233

\average[1]{1,3.7,5,3.2*2,7.9} % would return 4.8.  the argument number is arbitrary but li

\message{\average[5]{2,3}}

\bye

很难跟随你沿着 fp 变量的旅程……

但是,可以定义一个可扩展的\average命令来应对各种方法。

\documentclass{article}

\ExplSyntaxOn

\NewExpandableDocumentCommand{\average}{O{20}m}
 {% #1 = accuracy, #2 = list of fp expressions
  \xcn_average:nn {#1} {#2}
 }

\cs_new:Nn \xcn_average:nn
 {
  \fp_eval:n { round ( 0 \clist_map_function:nN {#2} \__xcn_average_item:n , #1 ) }
 }
\cs_new:Nn \__xcn_average_item:n
 {
  + \fp_eval:n {#1}
 }

%% method with fp variables
\fp_new_variable:n { aaa }
\fp_set_variable:nn { aaa } { 3.5 }

% method with commands
\newcommand{\bbb}{4.5}

\ExplSyntaxOff

\begin{document}

\average{2,4,aaa,\bbb,pi}

\average[3]{2,4,aaa,\bbb,pi}

\edef\test{\average[4]{2,4,aaa,\bbb,pi}}
\texttt{\meaning\test}

\end{document}

5

  • 好像我表达不清楚,我的目的是,如果我计算z=2*x+3*y,让x=5,y=6,然后定义一个可以计算z的函数,并将{5,6}作为列表供expl3使用,结果为2*5+3*6=28


    – 


  • 4
    这还不算是平均值,是吗?


    – 

  • 是的,这超出了主题的范围。


    – 

  • 什么O{20} 意思?保留20位小数?为什么中有一个0 round(0 \clist_…


    – 

  • @XCN 由于小数位数最多为 15,因此使用 20 与打印整数没什么不同。您可以决定始终舍入的开销是否比检查可选参数的开销更大。


    – 

如果重点是学习 expl3,那么这是错误的答案。但如果目标是使描述性统计数据变得简单,如平均值或中位数,或者更复杂,请考虑在 LateX 文档中包含 R 语言:

文件名:mwe.Rnw (本地,在 Overleaf 中使用mwe.Rtex )

\documentclass{article}
\parskip1em\parindent0pt
\begin{document}
<<echo=F>>=
require(knitr)
@
Mean of \Sexpr{combine_words(c(1,3.7,5))} would return roughly
\Sexpr{round(mean(c(1,3.7,5)),2)} (more precisely,
\Sexpr{mean(c(1,3.7,5))})  
<<data,echo=F>>=
# complex data better in a object x
x <- c(1,3.7,5,3.2*2,7.9)
@
Mean of x  values (\Sexpr{x}) is \Sexpr{mean(x)} with a SD of
\Sexpr{sd(x)} (rounded \Sexpr{round(sd(x),1)}) but the median is
\Sexpr{median(x)}. 
<<echo=F,fig.cap="Average of x in a box and wisker plot",fig.pos="h!">>=
boxplot(x,xlab="My x values")
@
\end{document}

0