当对负操作数使用 ^ 或 ** 时,LaTeX3 浮点 sqrt() 似乎不起作用

当对负操作数使用 ^ 或 ** 时,LaTeX3 浮点 sqrt() 似乎不起作用

我正在开发一个解析器来计算向量的大小,似乎 sqrt() 函数在对包含对负数进行运算的 ^ 或 ** 运算符的表达式进行操作时会引发错误。这是我的 MWE:

\documentclass{article}

\usepackage{expl3}
\usepackage{xparse}
\ExplSyntaxOn
\cs_new:Npn \l_my_parsevector #1 #2 {%
  \clist_set:Nn \l_tmpa_clist { #2 } % copy the vector to a clist
  \clist_pop:NN \l_tmpa_clist {\x}   % get the leftmost item
  %\fp_zero_new:c { l__#1_fp }        % new fp variable
  \fp_set:cn { l__#1_fp } {\x}       % assign it the first component
  %[\x]
  \clist_pop:NN \l_tmpa_clist {\y}   % get the leftmost item
  %\fp_zero_new:c { l__#1_fp }        % new fp variable
  \fp_set:cn { l__#1_fp } {\y}       % assign it the second component
  %[\y]
  \clist_pop:NN \l_tmpa_clist {\z}   % get the leftmost item
  %\fp_zero_new:c { l__#1_fp }        % new fp variable
  \fp_set:cn { l__#1_fp } {\z}       % assign it the third component
  %[\z]
}%
\NewDocumentCommand{\VectorMagnitude}{ O{a} m }{%
  \l_my_parsevector{#1}{#2}
  %\fp_eval:n { sqrt(\x*\x+\y*\y+\z*\z) } % always gives correct result
  \fp_eval:n { sqrt(\x^2+\y^2+\z^2) }     % Invalid operation sqrt(-16)
}%
\ExplSyntaxOff

\begin{document}
\VectorMagnitude{0,-4,0}
\end{document}

当前文档的第 213 页interface3似乎表明这是预期的行为,但表述得令人困惑。这种语法不起作用的原因是什么?我注意到,在两种情况下,将 -4 更改为 4 都会产生正确的结果。

答案1

您应该这样做(\x)^2以保护可能的减号。如果没有括号,您将得到-4^2正确评估为的结果-16

另一方面,你可以做得更好:

\documentclass{article}

\usepackage{expl3}
\usepackage{xparse}

\ExplSyntaxOn
\NewExpandableDocumentCommand{\VectorMagnitude}{O{15}m}
 {
  \fp_eval:n
   {
    round ( sqrt( 0 \clist_map_function:nN { #2 } \latexerexetal_square:n ) , #1 )
   }
 }
\cs_new:Nn \latexerexetal_square:n { + (#1)^2 }
\ExplSyntaxOff

\begin{document}

\VectorMagnitude{0,-4,0}

\VectorMagnitude{1,1,1}

\VectorMagnitude{3,4,0}

\VectorMagnitude[4]{3,4,0,-1,3,pi}

\end{document}

在此处输入图片描述

该命令是完全可扩展的;例如

\edef\test{\VectorMagnitude[4]{3,4,0,-1,3,pi}}

将导致\test具有6.6985替换文本。


关于代码的一些注释。函数名不应以 开头l_,因为 是变量的保留名称。它还应该具有参数的签名,因此您的代码\l_my_parsevector实际上应该是

\my_parsevector:nn

并且应该用 来定义\cs_new_protected:Npn,因为它进行赋值。

还应\clist_pop_left:NN跟随着一个 clist 变量和一个 tl 变量,两者都没有括号;\x不能用作tl变量的名称。

如果你想提取 clist 变量中的第三个项目并将其设置为 fp 变量,那么更简单的说法是

\fp_set:Nn \l_tmpa_fp { \clist_item:Nn \l_tmpa_clist { 3 } }

而不是一个接一个地弹出项目。但我建议的方法要简单得多。

我们\clist_map_function:nN { #1 } \latexerexetal_square:n一举夺得

\latexerexetal_square:n { 0 } \latexerexetal_square:n { -4 } \latexerexetal_square:n { 0 }

在下一阶段的扩展中,这将变成

+ (0)^2 + (-4)^2 + (0)^2

首字母0仍然位于所有内容的前面(实际上,它并不是真正必要的);因此表达式的评估是正确的。

由于使用的所有东西都是完全可扩展的,我可以\VectorMagnitude用 来定义\NewExpandableDocumentCommand。可选参数是舍入的位数。

相关内容