\int_case:nnTF 的浮点等效值

\int_case:nnTF 的浮点等效值

expl3 中有几种类型化的模式匹配命令,例如\tl_case\str_case,包括\int_case,但值得注意的是,似乎没有\fp_case与匹配浮点值相对应的命令。我正在使用当前的l3kernel 文档以供参考。

我是否遗漏了一些琐碎的东西,或者\fp_case目前确实遗漏了什么?如果是这样,我将非常感激一些关于如何实现它的指示,因为我对使用 LaTeX3 内部组件还不熟悉。TIA。

答案1

它不存在,因为它没有太多实际意义。特定计算中的任何不准确性都会导致您的代码执行不同的操作,即使3.14159265358979323.1415926535897931实际上没有区别。例如,这个:

\fp_compare:nNnTF { sin(2pi) } = { 0 }
  { \TRUE } { \FALSE }

结果为假,尽管从分析上来说它应该是正确的。

浮点相等通常是错误的操作。大多数情况下,浮点相等是可行的,因为浮点引擎非常擅长其工作,但如果你给它们一个棘手的情况,它就会得到错误的结果。事实上,当我以前编写 Fortran 代码时,gfortran会引发有关浮点相等的编译时警告(我没有安装它来举例,抱歉)。

问题在于\fp_case:nn它只使用相等性测试来选择一个案例,这可能会起作用,是的,但也可能出错,所以主要是为了稳定性,它不存在。

话虽如此,我们\bool_case_true:n(TF)\bool_case_false:n(TF),您可以使用它们来模拟\fp_case:nn检查值是否在设定的容差范围内匹配的。这是一个概念验证(未实现真/假分支):

\documentclass{article}
\usepackage{expl3}
\ExplSyntaxOn
\fp_new:N \l_arets_tol_fp
\fp_set:Nn \l_arets_tol_fp { 1e-6 }
\cs_new:Npn \arets_fp_case:nn #1
  {
    \exp_args:Nf \__arets_fp_case:nn
      { \fp_eval:n {#1} }
  }
\cs_new:Npn \__arets_fp_case:nn #1#2
  {
    \tl_map_tokens:nn {#2}
      { \__arets_fp_case_split:nn {#1} }
  }
\cs_new:Npn \__arets_fp_case_split:nn #1#2
  { \__arets_fp_case:nnn {#1} #2 }
\cs_new:Npn \__arets_fp_case:nnn #1#2#3
  {
    \fp_compare:nT
      {
        #1 > #2 - \l_arets_tol_fp &
        #1 < #2 + \l_arets_tol_fp
      }
      { \tl_map_break:n {#3} }
  }

% ------------ Test macro
\cs_new_protected:Npn \test #1
  {
    $
    \arets_fp_case:nn {#1}
      {
        { { pi }   { \pi } }
        { { exp(1) } { e } }
      }
    = \fp_eval:n {#1} $
  }

\ExplSyntaxOff
\begin{document}
\test{3.1415926}

\test{2.7182818}

\test{1.6180339}
\end{document}

打印结果为:

在此处输入图片描述

答案2

您可以使用\str_case:nn或,\str_case_e:nn只要所有浮点数都以十进制表示即可。

\token_case_meaning:Nn只要您只比较浮点变量,您也可以使用。

当然,测试浮点相等性的常见问题(正如 Phelype Oleinik 所指出的)仍然存在。

\documentclass{article}

\ExplSyntaxOn

\cs_new:Npn \__my_fp_case:nn #1#2
  { \str_case_e:en { \fp_to_decimal:n {#1} } {#2} }
\cs_new:Npn \__my_fp_case_test:n #1
  {
    \__my_fp_case:nn {#1}
      {
        { \fp_to_decimal:N \c_one_fp } { <code1> }
        { 2 } { <code2> }
        { \fp_to_decimal:n { 0.6 * 2 } } { <code3> }
        { \fp_to_decimal:n { 1.2 ^ 2 } } { <code4> }
      }
  }
\NewExpandableDocumentCommand \fpcasetest { m }
  { \__my_fp_case_test:n {#1} }

\ExplSyntaxOff


\begin{document}

\fpcasetest{1}

\fpcasetest{2}

\fpcasetest{1.2}

\fpcasetest{1.44}

\bigskip

% just for demonstration; please don't use ExplSyntax at document level
\ExplSyntaxOn
\cs_new:Npn \__my_fp_case_token_meaning:N #1
  {
    \token_case_meaning:Nn #1
      {
        \c_zero_fp { <code1> }
        \c_one_fp  { <code2> }
        \c_e_fp    { <code3> }
        \c_pi_fp   { <code4> }
      }
  }
\__my_fp_case_token_meaning:N \c_zero_fp
\par
\fp_set:Nn \l_tmpa_fp {1}
\__my_fp_case_token_meaning:N \l_tmpa_fp
\par
\__my_fp_case_token_meaning:N \c_e_fp
\par
\fp_set_eq:NN \l_tmpa_fp \c_pi_fp
\__my_fp_case_token_meaning:N \l_tmpa_fp
\par
\ExplSyntaxOff

\end{document}

在此处输入图片描述

相关内容