编写步进函数 - 第 2 部分

编写步进函数 - 第 2 部分

根据egreg在这个问题中给出的宏: 编程阶跃函数

我得到了一个程序,它测试在bone、btwo、bthree、bfour这几个数字之间,哪个间隔是数字 \alpha。我使用这个宏来计算简单情况下统计数据的百分位数。我写了这个程序:

\documentclass{article}
\usepackage{xparse}

\ExplSyntaxOn

\NewDocumentCommand{\definestepfunction}{mmm}
 { % #1 is the function's name
   % #2 is the semicolon separated subdivision
   % #3 is the semicolon separated list of values
  \faouzi_step_define:nnn { #1 } { #2 } { #3 }
 }

\cs_new_protected:Nn \faouzi_step_define:nnn
 {
  \tl_clear:N \l_faouzi_step_temp_tl
  \seq_set_split:Nnn \l_faouzi_step_division_seq { ; } { #2 }
  \seq_set_split:Nnn \l_faouzi_step_values_seq { ; } { #3 }
  \int_step_inline:nnnn { 1 } { 1 } { \seq_count:N \l_faouzi_step_division_seq - 1 }
   {
    \tl_put_right:Nx \l_faouzi_step_temp_tl
     {
      \exp_not:N \faouzi_step_compare:nnnn { ########1 }
       { \seq_item:Nn \l_faouzi_step_division_seq { ##1 } }
       { \seq_item:Nn \l_faouzi_step_division_seq { ##1 + 1 } }
       { \seq_item:Nn \l_faouzi_step_values_seq { ##1 } }
     }
   }
  \cs_new:cV { faouzi_step_ \cs_to_str:N #1 :n } \l_faouzi_step_temp_tl
  \cs_new_eq:Nc { #1 } { faouzi_step_ \cs_to_str:N #1 :n }
 }

\cs_generate_variant:Nn \cs_new:cn { cV }

\cs_new:Nn \faouzi_step_compare:nnnn
 {
  \fp_compare:nT { #2 <= #1 < #3 } { #4 }
 }

\ExplSyntaxOff

\usepackage{fp}
%%% Bounds of intervals
\FPeval\bone{0}\FPeval\btwo{1}\FPeval\bthree{2}\FPeval\bfour{3}
%%% Example of number
\FPeval\alpha{1.7}

\definestepfunction{\test}{\bone;\btwo;\bthree;\bfour}{
$\bone \leq \alpha < \btwo \Rightarrow \alpha \in [\bone,\btwo[$
;
$\btwo \leq \alpha < \bthree \Rightarrow \alpha \in [\btwo,\bthree[$
;
$\bthree \leq \alpha < \bfour \Rightarrow \alpha \in [\bthree,\bfour[$
}

\begin{document}
\test{\alpha}
\end{document}

在输出中给出(取决于 \alpha)良好的表达式: 在此处输入图片描述

但是现在,由于输出取决于 \alpha,对于 \alpha 的另一个值,我必须为每个值编写一个步进函数。这为该程序提供了两个值 \alphaone 和 \alphatwo 的两个测试,testone 和 testtwo:

\documentclass{article}
\usepackage{xparse}

\ExplSyntaxOn

\NewDocumentCommand{\definestepfunction}{mmm}
 { % #1 is the function's name
   % #2 is the semicolon separated subdivision
   % #3 is the semicolon separated list of values
  \faouzi_step_define:nnn { #1 } { #2 } { #3 }
 }

\cs_new_protected:Nn \faouzi_step_define:nnn
 {
  \tl_clear:N \l_faouzi_step_temp_tl
  \seq_set_split:Nnn \l_faouzi_step_division_seq { ; } { #2 }
  \seq_set_split:Nnn \l_faouzi_step_values_seq { ; } { #3 }
  \int_step_inline:nnnn { 1 } { 1 } { \seq_count:N \l_faouzi_step_division_seq - 1 }
   {
    \tl_put_right:Nx \l_faouzi_step_temp_tl
     {
      \exp_not:N \faouzi_step_compare:nnnn { ########1 }
       { \seq_item:Nn \l_faouzi_step_division_seq { ##1 } }
       { \seq_item:Nn \l_faouzi_step_division_seq { ##1 + 1 } }
       { \seq_item:Nn \l_faouzi_step_values_seq { ##1 } }
     }
   }
  \cs_new:cV { faouzi_step_ \cs_to_str:N #1 :n } \l_faouzi_step_temp_tl
  \cs_new_eq:Nc { #1 } { faouzi_step_ \cs_to_str:N #1 :n }
 }

\cs_generate_variant:Nn \cs_new:cn { cV }

\cs_new:Nn \faouzi_step_compare:nnnn
 {
  \fp_compare:nT { #2 <= #1 < #3 } { #4 }
 }

\ExplSyntaxOff

\usepackage{fp}
%%% Bounds of intervals
\FPeval\bone{0}\FPeval\btwo{1}\FPeval\bthree{2}\FPeval\bfour{3}
%%% Example of number
\FPeval\alphaone{1.7}\FPeval\alphatwo{2.3}

\definestepfunction{\testone}{\bone;\btwo;\bthree;\bfour}{
$\bone \leq \alphaone < \btwo \Rightarrow \alphaone \in [\bone,\btwo[$
;
$\btwo \leq \alphaone < \bthree \Rightarrow \alphaone \in [\btwo,\bthree[$
;
$\bthree \leq \alphaone < \bfour \Rightarrow \alphaone \in [\bthree,\bfour[$
}

\definestepfunction{\testtwo}{\bone;\btwo;\bthree;\bfour}{
$\bone \leq \alphatwo < \btwo \Rightarrow \alphatwo \in [\bone,\btwo[$
;
$\btwo \leq \alphatwo < \bthree \Rightarrow \alphatwo \in [\btwo,\bthree[$
;
$\bthree \leq \alphatwo < \bfour \Rightarrow \alphatwo \in [\bthree,\bfour[$
}
\begin{document}
\testone{\alphaone}

\testtwo{\alphatwo}

\end{document}

给出了良好的输出:

在此处输入图片描述

现在,很明显我不想为我的测试的每个值写一个输出。所以问题是:我如何获得一个宏,它为每个 \alpha 值提供良好的结果,因此阶跃函数 \test 为每个 \alpha 提供相同的输出,其中命令 \test(\alpha) 给出如下内容:

$a\leq \alpha < b \Rightarrow \alpha \in [a,b[$

答案1

只需适当设置第三个参数\definetestfunction,您就可以用它#1来引用传递给的参数\test(或您为该函数选择的任何名称)。

\documentclass{article}
\usepackage{xparse}

\ExplSyntaxOn

\NewDocumentCommand{\definestepfunction}{mmm}
 { % #1 is the function's name
   % #2 is the semicolon separated subdivision
   % #3 is the semicolon separated list of values
  \faouzi_step_define:nnn { #1 } { #2 } { #3 }
 }

\cs_new_protected:Nn \faouzi_step_define:nnn
 {
  \tl_clear:N \l_faouzi_step_temp_tl
  \seq_set_split:Nnn \l_faouzi_step_division_seq { ; } { #2 }
  \seq_set_split:Nnn \l_faouzi_step_values_seq { ; } { #3 }
  \int_step_inline:nnnn { 1 } { 1 } { \seq_count:N \l_faouzi_step_division_seq - 1 }
   {
    \tl_put_right:Nx \l_faouzi_step_temp_tl
     {
      \exp_not:N \faouzi_step_compare:nnnn { ########1 }
       { \seq_item:Nn \l_faouzi_step_division_seq { ##1 } }
       { \seq_item:Nn \l_faouzi_step_division_seq { ##1 + 1 } }
       { \seq_item:Nn \l_faouzi_step_values_seq { ##1 } }
     }
   }
  \cs_new:cV { faouzi_step_ \cs_to_str:N #1 _aux:n } \l_faouzi_step_temp_tl
  \cs_new:cx { faouzi_step_ \cs_to_str:N #1 :n }
   {
    \exp_not:N \faouzi_step_check:nnnn
     { \cs_to_str:N #1 }
     { ##1 }
     { \seq_item:Nn \l_faouzi_step_division_seq { 1 } }
     { \seq_item:Nn \l_faouzi_step_division_seq { -1 } }
   }
  \cs_new_eq:Nc { #1 } { faouzi_step_ \cs_to_str:N #1 :n }
 }

\cs_generate_variant:Nn \cs_new:cn { cV }

\cs_new:Nn \faouzi_step_compare:nnnn
 {
  \fp_compare:nT { #2 <= #1 < #3 } { #4 }
 }
\cs_new:Nn \faouzi_step_check:nnnn
 {
  \fp_compare:nTF { #3 <= #2 < #4 }
   {
    \use:c { faouzi_step_#1_aux:n } { #2 }
   }
   {
    \msg_error:nnnnn { faouzi/step } { out-of-bounds } { #2 } { #3 } { #4 }
   }
 }

\msg_new:nnnn { faouzi/step } { out-of-bounds }
 {% error message
  Value~#1~out~of~bounds~[#2,#3)
 }
 {% help message
  The~given~value~'#1'~is~out~of~bounds,~the~function~
  is~defined~in~the~interval~[#2,#3)
 }

\ExplSyntaxOff

\definestepfunction{\test}{0;1;2;3}
 {
  0\le #1<1 \Rightarrow #1\in[0,1);
  1\le #1<2 \Rightarrow #1\in[1,2);
  2\le #1<3 \Rightarrow #1\in[2,3);
 }

\newcommand{\alphaone}{1.7}
\newcommand{\alphatwo}{2.3}

\begin{document}

$\test{\alphaone}$

$\test{\alphatwo}$

\end{document}

在此处输入图片描述

我建议不要使用fp,最重要的是不要重新定义\alpha

改良版

在此版本中,定义主体中提供了命令\LOWER\UPPER,表示匹配间隔的下限和上限。此外,如果定义主体只有一个项目,则将对所有间隔重复此操作。

\documentclass{article}
\usepackage{xparse}

\ExplSyntaxOn

\DeclareExpandableDocumentCommand{\fpeval}{m}
 {
  \fp_eval:n { #1 }
 }

\NewDocumentCommand{\definestepfunction}{mmm}
 { % #1 is the function's name
   % #2 is the semicolon separated subdivision
   % #3 is the semicolon separated list of values
   \faouzi_step_define:nnn { #1 } { #2 } { #3 }
 }

\NewDocumentCommand{\LOWER}{}
 {
  \tl_use:N \l_faouzi_step_lower_tl
 }
\NewDocumentCommand{\UPPER}{}
 {
  \tl_use:N \l_faouzi_step_upper_tl
 }

\tl_new:N \l_faouzi_step_lower_tl
\tl_new:N \l_faouzi_step_upper_tl

\cs_new_protected:Nn \faouzi_step_define:nnn
 {
  \tl_clear:N \l_faouzi_step_temp_tl
  \seq_set_split:Nnn \l_faouzi_step_division_seq { ; } { #2 }
  \seq_set_split:Nnn \l_faouzi_step_values_seq { ; } { #3 }
  \int_compare:nT { \seq_count:N \l_faouzi_step_values_seq == 1 }
   {
    \prg_replicate:nn { \seq_count:N \l_faouzi_step_division_seq - 2 }
     {
      \seq_put_right:Nn \l_faouzi_step_values_seq { #3 }
     }
   }
  \int_step_inline:nnnn { 1 } { 1 } { \seq_count:N \l_faouzi_step_division_seq - 1 }
   {
    \tl_put_right:Nx \l_faouzi_step_temp_tl
     {
      \exp_not:N \faouzi_step_compare:nnnn { ########1 }
       { \seq_item:Nn \l_faouzi_step_division_seq { ##1 } }
       { \seq_item:Nn \l_faouzi_step_division_seq { ##1 + 1 } }
       { \seq_item:Nn \l_faouzi_step_values_seq { ##1 } }
     }
   }
  \cs_new:cV { faouzi_step_ \cs_to_str:N #1 _aux:n } \l_faouzi_step_temp_tl
  \cs_new:cx { faouzi_step_ \cs_to_str:N #1 :n }
   {
    \exp_not:N \faouzi_step_check:nnnn
     { \cs_to_str:N #1 }
     { ##1 }
     { \seq_item:Nn \l_faouzi_step_division_seq { 1 } }
     { \seq_item:Nn \l_faouzi_step_division_seq { -1 } }
   }
  \cs_new_eq:Nc { #1 } { faouzi_step_ \cs_to_str:N #1 :n }
 }

\cs_generate_variant:Nn \cs_new:cn { cV }

\cs_new_protected:Nn \faouzi_step_compare:nnnn
 {
  \tl_set:Nn \l_faouzi_step_lower_tl { #2 }
  \tl_set:Nn \l_faouzi_step_upper_tl { #3 }
  \fp_compare:nT { #2 <= #1 < #3 } { #4 }
 }
\cs_new:Nn \faouzi_step_check:nnnn
 {
  \fp_compare:nTF { #3 <= #2 < #4 }
   {
    \use:c { faouzi_step_#1_aux:n } { #2 }
   }
   {
    \msg_error:nnnnn { faouzi/step } { out-of-bounds } { #2 } { #3 } { #4 }
   }
 }

\msg_new:nnnn { faouzi/step } { out-of-bounds }
 {% error message
  Value~#1~out~of~bounds~[#2,#3)
 }
 {% help message
  The~given~value~'#1'~is~out~of~bounds,~the~function~
  is~defined~in~the~interval~[#2,#3)
 }

\ExplSyntaxOff

\newcommand{\alphaone}{1.7}
\newcommand{\alphatwo}{2.3}
\newcommand{\bzero}{0}
\newcommand{\bone}{1.7}
\newcommand{\btwo}{2.3}
\newcommand{\bthree}{5.6}

\definestepfunction{\testA}{0;1;2;3}
 {
  \LOWER\le #1<\UPPER \Rightarrow #1\in[\LOWER,\UPPER)
 }

\definestepfunction{\testB}{\bzero;\bone;\btwo;\bthree}
 {
  $\LOWER\le#1<\UPPER$ then the mid-interval is
  $\frac{\LOWER+\UPPER}{2}=\fpeval{(\LOWER+\UPPER)/2}$
 }

\definestepfunction{\testC}{\bzero;\bone;\btwo;\bthree}
 {
  #1 is in the first interval;
  #1 is in the second interval;
  #1 is in the third interval
 }

\begin{document}

$\testA{\alphaone}$

$\testA{\alphatwo}$

\testB{1.5}

\testB{1.7}

\testB{2.6}

\testC{1.5}

\testC{1.7}

\testC{2.6}

\end{document}

在此处输入图片描述

答案2

这是一个不使用任何特殊包的解决方案:

\newcount\tmpnum
\def\definestepfunction#1#2#3{%
   \def#1##1{\def\sfv{##1}\dostepfunction#2;;\end#3\endgame}
}
\def\dostepfunction#1;{%
   \ifdim\sfv pt<#1pt \outofrange \fi
   \dostepfunctionA#1;%
}
\def\dostepfunctionA#1;#2;{%   
   \ifx;#2;\outofrange \fi
   \advance\tmpnum by1
   \ifdim\sfv pt<#2pt \def\sfl{#1}\def\sfr{#2}\dostepfunctionB \fi
   \dostepfunctionA#2;%
}
\def\dostepfunctionB#1\end{\fi\dostepfunctionC}
\def\dostepfunctionC#1;#2{%
   \advance\tmpnum by-1
   \ifnum\tmpnum=0 #1\endgame \fi
   \ifx\endgame#2#1\endgame \fi
   \dostepfunctionC#2
}
\def\outofrange#1\endgame{\fi 
   \errmessage{the value \sfv\space is out of the range}%
}
\def\endgame#1\dostepfunctionC#2\endgame{\fi}
%%% the test:
\definestepfunction\test{0;1;2;3}
{
  0\le \sfv<1 \Rightarrow \sfv\in[0,1);
  1\le \sfv<2 \Rightarrow \sfv\in[1,2);
  2\le \sfv<3 \Rightarrow \sfv\in[2,3);
}
$\test{1.2}$\par
$\test{2.3}$\par
$\test{0}$

%OR
\definestepfunction\test{0;1;2;3}
{
  \sfl\le \sfv<\sfr \Rightarrow \sfv\in[\sfl,\sfr);
}
$\test{1.2}$\par
$\test{2.3}$\par
$\test{0}$
\bye

答案3

根据 John Kormylo 给出的答案,并阅读了 pgf 的文档后,我得到了一个基于 pgfmaths 的更简单的解决方案,该解决方案适用于更一般的情况。以下程序测试间隔在哪个值中,有界限的间隔为(例如)\bzero=0、\bone=1.7、\btwo=2.3、\bthree=5.6。

\documentclass{article}
\usepackage{tikz} % Need the hole package for the command \pgfmathprintnumber
%\usepackage{pgfmath}% part of the tikz package
%\usepackage{pgffor}% part of the tikz package
\usepackage{geometry}
 \geometry{paperwidth=165mm, paperheight=75mm}
\pagestyle{empty}

\newcommand{\bzero}{0}
\newcommand{\bone}{1.7}
\newcommand{\btwo}{2.3}
\newcommand{\bthree}{5.6}
\def\myarray{{\bzero,\bone,\btwo,\bthree}}

\newcommand{\steps}[1]% #1 = unknown real (text)
{\bgroup% local definitions
\foreach \i [evaluate=\i as \j using int(\i+1)] in {0,...,2} %j:=i+1
    {
        \pgfmathparse{\myarray[\i]}
        \let\minbound=\pgfmathresult 
        \pgfmathparse{\myarray[\j]}
        \let\maxbound=\pgfmathresult 
        \pgfmathparse
            {
                ifthenelse(and(notless(#1,\myarray[\i])==1,less(#1,\myarray[\j])==1),   
                "$\minbound \leq #1 < \maxbound$ then the mid-interval is 
                $\displaystyle\frac{\minbound + \maxbound}{2}=$",
                "")
            }
        \pgfmathresult 
        % An example of some calculus
        \pgfmathparse
            {
                ifthenelse(and(notless(#1,\myarray[\i])==1,less(#1,\myarray[\j])==1),   
                (\minbound+\maxbound)/2, 
                "")
            }
        \pgfmathresult
    }
\egroup}

\begin{document}
\steps{1.5}
\vspace{.5cm}
\\
\steps{1.7}
\vspace{.5cm}
\\
\steps{2.6}
\end{document}

对值 1.5、1.7 和 2.6 的测试给出了合适输出的示例,混合了文字表达式和一些数值计算: 在此处输入图片描述

答案4

这是一个 pgfmath 版本:

\documentclass{article}
\usepackage{pgfmath}% part of the tikz package

\newcommand{\steps}[1]% #1 = unknown real (text)
{\bgroup% local definitions
 \pgfmathint{#1}% or \pgfmathparse{int(#1)}
 \let\less=\pgfmathresult
 \pgfmathparse{int(ceil(#1))}
 \let\more=\pgfmathresult
 $\less \leq #1 \leq \more \Rightarrow #1 \in [\less,\more]$
\egroup}

\begin{document}
\steps{1.7}

\steps{2.3}

\end{document}

输出


\if \else \fi对于这个问题,使用纯 TeX比使用ifthenelsefrom更容易pgfmath

\documentclass{article}
\usepackage{tikz} % Need the whole package for the command \pgfmathprintnumber
%\usepackage{pgfmath}% part of the tikz package
%\usepackage{pgffor}% part of the tikz package
\usepackage{geometry}
 \geometry{paperwidth=165mm, paperheight=75mm}
\pagestyle{empty}

\def\myarray{{0,1.7,2.3,5.6}}

\newcommand{\steps}[1]% #1 = unknown real (text)
{\bgroup% local definitions
\foreach \i [evaluate=\i as \j using int(\i+1)] in {0,...,2} %j:=i+1
    {
        \pgfmathparse{\myarray[\i]}%
        \let\minbound=\pgfmathresult 
        \pgfmathparse{\myarray[\j]}%
        \let\maxbound=\pgfmathresult 
        \pgfmathparse{and(notless(#1,\minbound)==1,less(#1,\maxbound)==1)}%
        \ifnum\pgfmathresult=1\relax% actually \if\pgfmathresult 1 would have been faster
          \pgfmathparse{(\minbound+\maxbound)/2}%
          $\minbound \leq #1 < \maxbound$ then the mid-interval is 
            $\displaystyle\frac{\minbound + \maxbound}{2}=\pgfmathprintnumber{\pgfmathresult}$
        \fi
    }
\egroup}

\begin{document}
\noindent
\steps{1.5}
\vspace{.5cm}
\\
\steps{1.7}
\vspace{.5cm}
\\
\steps{2.6}
\end{document}

相关内容