根据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 的另一个值,我必须为每个值编写一个步进函数。这为该程序提供了两个值 \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}
答案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比使用ifthenelse
from更容易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}