带有浮点计算的普通 TeX 宏

带有浮点计算的普通 TeX 宏

我正在尝试采用这个 TeX 片段并将其用作宏的基础。

\centerline{\def\epsfsize#1#2{0.7#1} \epsfbox{1.01couet.eps}}

我正在努力解决一些需要解决的问题,因为我实际上正在重新定义一个填充相当大的项目的宏。我认为我可以做的是类似以下的事情:

\def\myfig#1#2#3#4{\dimen1=#4 \divide\dimen1 by 1000
\centerline{\def\epsfsize#1#2{{#4}{#1}} \epsfbox{#3}}}

这显然是错误的,可能有多种错误。我需要取参数 #4 并将其除以 1000 以用作比例(0.7 是上一个代码片段)。我知道 dimen1 不适用于无量纲量,但我找不到与此类主题相关的任何文档。

请注意,前两个参数暂时不会使用。

有没有涵盖这一问题的好的文档?

答案1

我的系统上没有1.01couet.eps。但是每个较新的 TeX 发行版都有example-image-a.eps

因此,在下面的代码片段中我将使用后者。;-)

如果我理解正确的话,\myfig的第四个参数表示任何因子。
该因子应除以 1000(十进制)。
其结果应作为比例因子传递到 的定义中\epsfsize

你可以通过维度来计算。要点是:

\the\dimension1根据单位得出维度寄存器 1 中保存的值pt

例如,\the\dimension130.74pt

因此,按照 进行计算pt,当使用结果作为数字而不是维度时,去掉短语pt

采用这种计算方法,结果不会很精确。

可能是其中一个包FP或者前列腺素(pgf 的数学引擎)对您来说很有趣。

下面的代码片段是否提供了或多或少正确的比例因子\epsfsize

\input epsf.tex

\long\def\PassFirstToSecond#1#2{#2{#1}}%
\long\def\firstoftwo#1#2{#1}%
\long\def\secondoftwo#1#2{#2}%

\begingroup
\catcode `P=12  % 
\catcode `T=12  %
\lowercase{%
  \def\x{%
    \def\RomannumeralDrivenRempt##1.##2PT{%
      0\ifnum##2>0 \expandafter\firstoftwo\else\expandafter\secondoftwo\fi
      { ##1.##2}{ ##1}%
    }%
  }%
}%
\expandafter\endgroup\x%
\def\RomannumeralDrivenStrippt{\expandafter\RomannumeralDrivenRempt\the}%

\def\myfig#1#2#3#4{%
  \begingroup
  \dimen1=#4pt %
  \dimen1=.001\dimen1 %
  \expandafter\endgroup
  \expandafter\centerline\expandafter{%
    \expandafter\PassFirstToSecond\expandafter{%
      \romannumeral\RomannumeralDrivenStrippt\dimen1 ##1%
    }{\def\epsfsize##1##2}%
    %%%
    \show\epsfsize
    %%%
    \epsfbox{#3}%
  }%
}%

\myfig{Unused 1}{Unused 2}{example-image-a.eps}{1000}

\myfig{Unused 1}{Unused 2}{example-image-a.eps}{700}

\myfig{Unused 1}{Unused 2}{example-image-a.eps}{200}

\myfig{Unused 1}{Unused 2}{example-image-a.eps}{40}

\bye


以下是相同的代码,但带有一些解释:

我认为这是\epsfsize来自哪里\epsfbox

\input epsf.tex

将第一个参数嵌套在第二个参数后面的括号中 - 这样,构成第一个参数的标记可以转换为构成第二个参数的标记的参数:

\long\def\PassFirstToSecond#1#2{#2{#1}}%

选择两个参数中的第一个:

\long\def\firstoftwo#1#2{#1}%

选择两个参数中的第二个:

\long\def\secondoftwo#1#2{#2}%

上面我写道:“...按照 进行计算pt,当使用结果不是维度而是数字时,删除短语pt“。问题是,使用\the\dimen1→时30.74pt,组成短语的字符标记pt不是类别代码 11(字母),而是类别代码 12(其他)。所以我们需要将p类别代码 12 和t类别代码 12 放入代码中,同时还要让这些字符在类别代码 11 中可用,以便它们可以在宏名称中使用。因此,在一个组内,暂时将这些字符的大写变体的类别代码更改为 12。从这些大写变体中,您可以通过 类别代码 12 获得小写变体\lowercase

\begingroup
\catcode `P=12  % 
\catcode `T=12  %
\lowercase{%
  \def\x{%
    \def\RomannumeralDrivenRempt##1.##2PT{%
      0\ifnum##2>0 \expandafter\firstoftwo\else\expandafter\secondoftwo\fi
      { ##1.##2}{ ##1}%
    }%
  }%
}%
\expandafter\endgroup\x%

根据上述定义\x

\def\x{%
    \def\RomannumeralDrivenRempt##1.##2pt{%
      0\ifnum##2>0 \expandafter\firstoftwo\else\expandafter\secondoftwo\fi
      { ##1.##2}{ ##1}%
    }%
}%

,但该分隔符pt后面的字符将属于类别代码 12(其他)。##2##2

因此,扩大\x定义后将\RomannumeralDrivenRempt

\def\RomannumeralDrivenRempt#1.#2pt{%
  0\ifnum#2>0 \expandafter\firstoftwo\else\expandafter\secondoftwo\fi
  { #1.#2}{ #1}%
}%

pt,其后面的字符为#2类别#2代码 12(其他)。(正如\x组内所定义的,它需要在结束组之前进行扩展,但要使传递的标记出现在结束组的\x标记后面。这就是in的用途。)\endgroup\expandafter\expandafter\endgroup\x

乍一看,这个定义看起来很奇怪。但如果\RomannumeralDrivenRempt在 之前\romanumeral和之后加上400.23pt,则会得到以下内容:

\romannumeral\RomannumeralDrivenRempt400.23pt

这反过来又产生:

步骤1:

% romannumeral-expansion in progress
\RomannumeralDrivenRempt400.23pt

第2步:

% romannumeral-expansion in progress
0\ifnum23>0 \expandafter\firstoftwo\else\expandafter\secondoftwo\fi
{ 400.23}{ 400}%

步骤3:

% romannumeral-expansion in progress
% \romannumeral finds the digit 0 and keeps searching for more digits
% or a space-token that terminates the number and gets discarded.
\ifnum23>0 \expandafter\firstoftwo\else\expandafter\secondoftwo\fi
{ 400.23}{ 400}%

步骤 4:\ifnum比较产生“真实”分支:

% romannumeral-expansion in progress
% \romannumeral found the digit 0 and keeps searching for more digits
% or a space-token that terminates the number and gets discarded.
\expandafter\firstoftwo\else\expandafter\secondoftwo\fi
{ 400.23}{ 400}%

步骤 5: \expandafter“命中” else 分支并且该 else 分支被删除:

% romannumeral-expansion in progress
% \romannumeral found the digit 0 and keeps searching for more digits
% or a space-token that terminates the number and gets discarded.
\firstoftwo
{ 400.23}{ 400}%

步骤 6: \firstoftwo获取第一个参数:

% romannumeral-expansion in progress
% \romannumeral found the digit 0 and keeps searching for more digits
% or a space-token that terminates the number and gets discarded.
<space token>400.23

步骤 7:现在\romannumeral“找到”空格标记。空格标记用于构成要转换\romannumeral为罗马数字的数字序列的终止符。该终止符将被丢弃,\romannumeral要转换的数字所采用的数字序列仅由数字组成,00不是正数,而 则按\romannumeral如下方式处理非正数:它只是吞下它们而不提供任何标记作为回报:

% romannumeral-expansion done. \romannumeral found the non-positive
% number 0 and silently swallowed it without delivering any token
% in return:
400.23

现在让我们继续代码:

上面我写道:“但是如果\RomannumeralDrivenRempt前面\romanumeral和后面都有类似的东西400.23pt,则会得到以下内容:......“因此需要一种机制来提供以下尾随短语:

\def\RomannumeralDrivenStrippt{\expandafter\RomannumeralDrivenRempt\the}%

(根据上述定义

\romannumeral\RomannumeralDrivenStrippt\dimen1 

产量:

步骤1:

%\romannumeral-expansion in progress
\RomannumeralDrivenStrippt\dimen1

第2步:

%\romannumeral-expansion in progress
\expandafter\RomannumeralDrivenRempt\the\dimen1

步骤 3: \expandafter“命中” \

%\romannumeral-expansion in progress
\RomannumeralDrivenRempt400.23pt

这是 扩展链的第一步\RomannumeralDrivenRempt

现在让我们继续代码:

\def\myfig#1#2#3#4{%
  \begingroup
  \dimen1=#4pt %
  \dimen1=.001\dimen1 %
  \expandafter\endgroup
  \expandafter\centerline\expandafter{%
    \expandafter\PassFirstToSecond\expandafter{%
      \romannumeral\RomannumeralDrivenStrippt\dimen1 ##1%
    }{\def\epsfsize##1##2}%
    %%%
    \show\epsfsize
    %%%
    \epsfbox{#3}%
  }%
}%

\myfig{Unused 1}{Unused 2}{example-image-a.eps}{1000}

\myfig{Unused 1}{Unused 2}{example-image-a.eps}{700}

\myfig{Unused 1}{Unused 2}{example-image-a.eps}{200}

\myfig{Unused 1}{Unused 2}{example-image-a.eps}{40}

\bye

让我们展示一下扩展链

\myfig{Unused 1}{Unused 2}{example-image-a.eps}{700}

步骤1:

  \begingroup
  \dimen1=700pt %
  \dimen1=.001\dimen1 %
  \expandafter\endgroup
  \expandafter\centerline\expandafter{%
    \expandafter\PassFirstToSecond\expandafter{%
      \romannumeral\RomannumeralDrivenStrippt\dimen1 ##1%
    }{\def\epsfsize##1##2}%
    %%%
    \show\epsfsize
    %%%
    \epsfbox{example-image-a.eps}%
  }%

步骤 2:在组内对 进行临时分配,\dimen1并进行“\expandafter跳跃”,以获取形成扩展的标记,\romannumeral\RomannumeralDrivenStrippt\dimen1 如上所述,在\endgroup关闭组的标记后面:

  \begingroup
  \dimen1=700pt %
  \dimen1=.001\dimen1 %
  \endgroup
  \centerline{%
    \PassFirstToSecond{%
      .7##1%
    }{\def\epsfsize##1##2}%
    %%%
    \show\epsfsize
    %%%
    \epsfbox{example-image-a.eps}%
  }%

组内的东西到达 TeX 的胃里并被消化。剩下的有趣的部分是:

  \centerline{%
    \PassFirstToSecond{%
      .7##1%
    }{\def\epsfsize##1##2}%
    %%%
    \show\epsfsize
    %%%
    \epsfbox{example-image-a.eps}%
  }%

步骤 3:由于\PassFirstToSecond这种情况,如下所示:

  \centerline{%
    \def\epsfsize##1##2{.7##1}%
    %%%
    \show\epsfsize
    %%%
    \epsfbox{example-image-a.eps}%
  }%

相关内容