我想将数组和fp
包一起使用。
\FPadd\xx{\somevalues(1)}{\somevalues(3)} 效果很好
\FPeval\xx{\somevalues(1)+\somevalues(1)}不工作
如何在数组中使用 \FPeval?
\documentclass{article}
\usepackage{fp}
\usepackage{siunitx,amsmath}
%\usepackage{xparse}
\ExplSyntaxOn
\NewDocumentCommand{\newarray}{m}
{
\seq_new:c { l_hafid_array_ \cs_to_str:N #1 _seq }
\cs_new:Npn #1 (##1)
{
\seq_item:cn { l_hafid_array_ \cs_to_str:N #1 _seq } { ##1 }
}
}
\NewDocumentCommand{\readarray}{mm}
{
\seq_set_split:cnn { l_hafid_array_#1_seq } { & } { #2 }
}
\cs_generate_variant:Nn \seq_set_split:Nnn { c }
\ExplSyntaxOff
\begin{document}
\newarray\somevalues
\readarray{somevalues}{1&2&3.5&4&5}
\begin{align*}
v_1 &= \somevalues(1)\\
v_2 &= \somevalues(2)\\
v_3 &= \somevalues(3)\\
v_4 &= \somevalues(4)\\
v_5 &= \somevalues(5)
\end{align*}
First number = \somevalues(1)\\
Second number = \somevalues(2)
\FPadd\xx{\somevalues(1)}{\somevalues(2)}
\FPeval{\xx}{round(xx,4)}%
sum of first two numbers = \xx
\FPeval\xx{\somevalues(1)+\somevalues(2)}
\FPeval{\xx}{round(xx,4)}%
sum of first two numbers = \xx
%
\newcount\count
\count=5
\FPset\ans{0}
\loop
%\somevalues(\count)\\
\FPadd\ans{\ans}{\somevalues(\count)}
%\FPeval\ans{\ans+\somevalues(\count)}
\advance \count by -1
\unless\ifnum \count<1
\repeat
%
\FPeval{\ans}{round(ans,4)}%
sum of all numbers = \ans
\end{document}
答案1
您的代码无法正常工作,因为包解析其输入的方式fp
。在 TeX 中,当您定义分隔宏时,分隔符文本必须总是存在,所以\somevalues
后面必须始终跟着一个(
,然后是一些文本,然后是一个结束的)
。当fp
尝试解析您的表达式时,它会分隔标记并在其间添加其他标记,那么您得到的错误是:
! Use of \somevalues doesn't match its definition.
<argument> \somevalues
\FP@gen@code {2}
因为接下来的\somevalues
是\FP@gen@code
,不是(
。
既然你正在使用,expl3
那么你可以使用它的l3fp
模块,它提供了一个可扩展的 FP 引擎。可扩展意味着你可以做
The~value~of~$\pi^2$~is:~\fp_eval:n { pi^2 }
甚至
\setlength{\textwidth}{\fp_eval:n{ 10*30 } pt}
这里我模拟了fp
的宏\FPadd
,\FPset
并\FPeval
使用 来l3fp
代替。请注意,这些模拟的宏不再可扩展。
现在您可以这样做,例如:
\FPset\ans{5}
\FPeval\ans{ans+10}
ans is: \ans % prints 15
每一个宏,比如说\ans
,用作 的第一个参数,都是\FP<something>
用操作的结果定义的,加上一个称为 的FP字,ans
是定义的,并将包含相同的值,因此在表达式中你可以使用\ans
或ans
。
警告!如果所涉及的宏已经定义,则不会执行任何验证,因此您可能会意外覆盖一些重要内容。这\FPeval\pi{6.283185}
可能不是一个好主意。
这是代码(我只改变了 FP 函数的定义;您的数组处理和测试代码是相同的):
\documentclass{article}
% \usepackage{fp}
\usepackage{siunitx,amsmath}
%\usepackage{xparse}
\ExplSyntaxOn
\NewDocumentCommand{\newarray}{m}
{
\seq_new:c { l_hafid_array_ \cs_to_str:N #1 _seq }
\cs_new:Npn #1 (##1)
{
\seq_item:cn { l_hafid_array_ \cs_to_str:N #1 _seq } { ##1 }
}
}
\NewDocumentCommand{\readarray}{mm}
{
\seq_set_split:cnn { l_hafid_array_#1_seq } { & } { #2 }
}
\cs_generate_variant:Nn \seq_set_split:Nnn { c }
% Stolen from l3fp:
\fp_new:N \l__sandu_temp_fp
\cs_set_protected:Npn \sandu_fp_name:nn #1 #2
{
\cs_undefine:c { c__sandu_#1_fp }
\fp_const:cn { c__sandu_#1_fp } { #2 }
\__sandu_define_fp_name:cn { c__sandu_#1_fp } { #1 }
}
\cs_new_protected:Npn \__sandu_define_fp_name:Nn #1 #2
{
\cs_set:cpn { __fp_parse_word_#2:N }
{ \exp_after:wN #1 \exp:w \exp_end_continue_f:w \__fp_parse_infix:NN }
}
\cs_generate_variant:Nn \__sandu_define_fp_name:Nn { c }
\cs_generate_variant:Nn \sandu_fp_name:nn { f }
% Emulating fp.sty
\NewDocumentCommand \FPadd {m mm}
{
\tl_set:Nx #1 { \fp_eval:n { #2 + #3 } }
\sandu_fp_name:fn { \cs_to_str:N #1 } { #1 }
}
\NewDocumentCommand \FPeval {m m}
{
\tl_set:Nx #1 { \fp_eval:n { #2 } }
\sandu_fp_name:fn { \cs_to_str:N #1 } { #1 }
}
\NewDocumentCommand \FPset {m m}
{
\tl_set:Nx #1 { \fp_eval:n { #2 } }
\sandu_fp_name:fn { \cs_to_str:N #1 } { #1 }
}
\ExplSyntaxOff
\begin{document}
\newarray\somevalues
\readarray{somevalues}{1&2&3.5&4&5}
\begin{align*}
v_1 &= \somevalues(1)\\
v_2 &= \somevalues(2)\\
v_3 &= \somevalues(3)\\
v_4 &= \somevalues(4)\\
v_5 &= \somevalues(5)
\end{align*}
First number = \somevalues(1)\\
Second number = \somevalues(2)
\FPadd\xx{\somevalues(1)}{\somevalues(2)}
\FPeval{\xx}{round(xx,4)}%
sum of first two numbers = \xx
\FPeval\xx{\somevalues(1)+\somevalues(2)}
\FPeval{\xx}{round(xx,4)}%
sum of first two numbers = \xx
%
\newcount\counter
\counter=5
\FPset\ans{0}
\loop
%\somevalues(\counter)\\
\FPadd\ans{\ans}{\somevalues(\counter)}
%\FPeval\ans{\ans+\somevalues(\counter)}
\advance \counter by -1
\unless\ifnum \counter<1
\repeat
%
\FPeval{\ans}{round(ans,4)}%
sum of all numbers = \ans
\end{document}
打印结果为:
PS:不要这样做,\newcount\count
因为您将重新定义 TeX 原语\count
。请使用其他名称。
答案2
不要使用\newcount
如果您不知道它的怪癖:例如,它不检查控制序列是否已定义。如果您想要另一个壮观的残骸,请尝试\newcount\box
。
你混淆了语法。比如
\newarray\somevalues
\setarray\somevalues{1&2&3}
\somevalues(1)
很时髦arrayjobx
,我不会用,因为它会让解析器感到困惑\fpeval
。更好的标准参数分隔符是括号。
fp
当您已经在使用时,无需再使用expl3
。
\documentclass{article}
\usepackage{siunitx,amsmath}
\usepackage{xparse,xfp}
\ExplSyntaxOn
\NewDocumentCommand{\newarray}{m}
{
\seq_new:c { l_hafid_array_#1_seq }
\cs_new:cpn { #1 } ##1
{
\seq_item:cn { l_hafid_array_#1_seq } { ##1 }
}
}
\NewDocumentCommand{\readarray}{mm}
{
\seq_set_split:cnn { l_hafid_array_#1_seq } { & } { #2 }
}
\cs_generate_variant:Nn \seq_set_split:Nnn { c }
\NewExpandableDocumentCommand{\sumarray}{O{15}m}
{
\fp_eval:n { round( \seq_use:cn { l_hafid_array_#2_seq } { + }, #1 ) }
}
\ExplSyntaxOff
\begin{document}
\newarray{somevalues}
\readarray{somevalues}{1&2&3.5&4&5}
\begin{align*}
v_1 &= \somevalues{1}\\
v_2 &= \somevalues{2}\\
v_3 &= \somevalues{3}\\
v_4 &= \somevalues{4}\\
v_5 &= \somevalues{5}
\end{align*}
First number = \somevalues{1}
Second number = \somevalues{2}
sum of first two numbers =
\fpeval{ round(\somevalues{1}+\somevalues{2},4) }
Sum of the array \sumarray[4]{somevalues}
Sum of the array \sumarray[0]{somevalues}
\end{document}
可选参数\sumarray
是四舍五入的位数。