在 TeX 中缩放胶水

在 TeX 中缩放胶水

是否有可能在 TeX 中缩放胶水?请考虑以下示例:

\newskip\foo
\newskip\bar

\foo=10pt plus 2pt minus 3pt
\bar=2.5\foo\relax
\showthe\foo
\showthe\bar

\bye

当将此代码输入到 TeX 中时,它将在日志文件中生成以下输出,显示在分配给 期间 \foo 的拉伸和收缩被丢弃\bar

> 10.0pt plus 2.0pt minus 3.0pt.
l.6 \showthe\foo

? 
> 25.0pt.
l.7 \showthe\bar

? 

显然\foo通过缩放转换为一个 dimen。有没有办法25.0pt 加 5.0pt 减 7.5pt因此?\multiply仅当因子为整数时才有效。至少有一种将胶合的拉伸或收缩复制到寄存器中的方法dimen就足够了。但我在 的第 12 章和第 15 章中没有找到合适的提示TeXBook

有人知道如何正确测量胶水的量吗?提前谢谢。

答案1

仅允许对 a 乘以小数因子<dimen>;当<glue>使用 a 时,它会被强制转换为 a <dimen>

语法<dimen>包括

<factor><unit of measure>

并且<unit of measure>可以是<internal dimen>(任意维度寄存器)或<internal glue>(任意粘合寄存器);参见 TeXbook,第 270 页。

另一方面,<glue>下一页的语法不允许<factor>

可以使用\skip0=2.5\skip2,但首先2.5\skip2将其强制转换为<dimen>,然后将结果强制转换为,<glue>从而失去可拉伸性和可收缩性分量。

一种解决方法是使用\multiply\divide,它们允许粘合,将因子转换为分数(但这可能导致溢出)。

假设可以使用 e-TeX,那么进行缩放的一组简单宏是

\def\scaleglue#1#2#3{% #1 is a factor, #2 is a glue specification, #3 is a glue register
  \scalegluetemp=#2\relax
  #3=#1\scalegluetemp plus \scalegluestretch{#1} minus \scaleglueshrink{#1}% 
  \relax\relax
}
\newskip\scalegluetemp

\def\scalegluestretch#1{%
  \strippt\dimexpr#1\gluestretch\scalegluetemp\relax
  \ifcase\gluestretchorder\scalegluetemp pt \or fil \or fill \or filll \fi
}
\def\scaleglueshrink#1#2{%
  \strippt\dimexpr#1\glueshrink\scalegluetemp\relax
  \ifcase\glueshrinkorder\scalegluetemp pt \or fil \or fill \or filll \fi
}

\def\strippt{\expandafter\dostrippt\the}
\begingroup\catcode`P=12 \catcode`T=12
  \lowercase{\endgroup\def\dostrippt#1PT{#1}}

\tt

\newskip\foo
\newskip\baz \baz=3pt minus -1filll

\scaleglue{1.2}{2pt plus 3pt}{\foo}\the\foo\par
\scaleglue{1.2}{2pt minus 3pt}{\foo}\the\foo\par
\scaleglue{1.2}{\baz}{\foo}\the\foo\par

\baz=0pt plus -1fil minus 3filll
\scaleglue{1.2}{\baz}{\foo}\the\foo\par

\bye

在此处输入图片描述


一种更简单的方法是\glueexpr(与 Heiko Oberdiek 的答案比较)

\def\scaleglue#1#2#3{% #1 is a factor, #2 is a glue expression, #3 a glue parameter
  #3=\glueexpr#2*\numexpr\dimexpr#1pt\relax\relax/65536\relax
}

\tt

\newskip\foo
\newskip\baz \baz=3pt minus -1filll

\scaleglue{1.2}{2pt plus 3pt}{\foo}\the\foo\par
\scaleglue{1.2}{2pt minus 3pt}{\foo}\the\foo\par
\scaleglue{1.2}{\baz}{\foo}\the\foo\par

\baz=0pt plus -1fil minus 3filll
\scaleglue{1.2}{\baz}{\foo}\the\foo\par

\bye

在此处输入图片描述


一种不同的方法不使用 e-TeX,因此速度更慢、更复杂。

\catcode`\@=11
\def\scaleglue#1#2#3{% #1 is a factor, #2 is a glue specification, #3 is a glue register
  \def\sg@factor{#1}%
  \sg@tempskip=#2\relax
  \dimen@=\sg@tempskip
  \edef\sg@tempa{\the\sg@tempskip}\edef\sg@tempb{\the\dimen@}%
  \ifx\sg@tempa\sg@tempb
    #3=#1\dimen@
  \else
    \sg@checkplusminus
    \sg@bothfalse\ifsg@plus\ifsg@minus\sg@bothtrue\fi\fi
    \ifsg@both
      \expandafter\sg@getcompboth\the\sg@tempskip\relax
    \else
      \ifsg@plus
        \edef\sg@minus{0\string p\string t}%
        \expandafter\sg@getcompplus\the\sg@tempskip\relax
      \else
        \edef\sg@plus{0\string p\string t}%
        \expandafter\sg@getcompminus\the\sg@tempskip\relax
      \fi
    \fi
    \sg@makept\sg@plusunit\sg@plus
    \sg@makept\sg@minusunit\sg@minus
    \dimen\z@=\sg@plus pt \dimen\z@=#1\dimen\z@
    \dimen\tw@=\sg@minus pt \dimen\tw@=#1\dimen\tw@
    #3=#1\sg@tempskip 
      plus \expandafter\sg@strippt\the\dimen\z@ \sg@plusunit
      minus \expandafter\sg@strippt\the\dimen\tw@ \sg@minusunit
    \relax
  \fi
}

\newskip\sg@tempskip
\newif\ifsg@minus
\edef\sg@plus{\string p\string l\string u\string s}
\edef\sg@minus{\string m\string i\string n\string u\string s}

\edef\sg@checkplusminus{%
  \noexpand\expandafter\noexpand\sg@checkplus\noexpand\the\sg@tempskip\sg@plus\relax
  \noexpand\expandafter\noexpand\sg@checkminus\noexpand\the\sg@tempskip\sg@minus\relax
}
\begingroup\edef\x{\endgroup\def\noexpand\sg@checkplus##1\sg@plus##2\relax}
\x{\if!#2!\sg@plusfalse\else\sg@plustrue\fi}
\begingroup\edef\x{\endgroup\def\noexpand\sg@checkminus##1\sg@minus##2\relax}
\x{\if!#2!\sg@minusfalse\else\sg@minustrue\fi}
\begingroup\edef\x{\endgroup\def\noexpand\sg@getcompboth##1\sg@plus##2\sg@minus##3\relax}
\x{\def\sg@plus{#2}\def\sg@minus{#3}}
\begingroup\edef\x{\endgroup\def\noexpand\sg@getcompplus##1\sg@plus##2\relax}
\x{\def\sg@plus{#2}}
\begingroup\edef\x{\endgroup\def\noexpand\sg@getcompminus##1\sg@minus##2\relax}
\x{\def\sg@minus{#2}}

\edef\sg@makept#1#2{%
  \noexpand\expandafter
  \noexpand\sg@makept@i
  \noexpand\expandafter#1%
  \noexpand\expandafter#2#2\string f\relax
}
\begingroup\edef\x{\endgroup\def\noexpand\sg@makept@i##1##2##3\string f##4\relax}
\x{%
  \if!#4!%
    \expandafter\sg@stripptx\expandafter#2#2\def#1{pt}%
  \else
    \def#2{#3}\sg@stripf#1#4%
  \fi
}
\begingroup\edef\x{%
  \endgroup\def\noexpand\sg@stripptx##1##2\string p\string t{\def##1{##2}}%
}\x
\begingroup\edef\x{%
  \endgroup\def\noexpand\sg@strippt##1\string p\string t{##1}%
}\x
\begingroup\edef\x{%
  \endgroup\def\noexpand\sg@stripf##1##2\string f{\def##1{f##2}}%
}\x
\newif\ifsg@plus
\newif\ifsg@minus
\newif\ifsg@both
\catcode`\@=12 % end of macros


%%% testing
\tt

\newskip\foo
\newskip\baz \baz=3pt minus -1filll

\scaleglue{1.2}{2pt plus 3pt}{\foo}\the\foo\par
\scaleglue{1.2}{2pt minus 3pt}{\foo}\the\foo\par
\scaleglue{1.2}{\baz}{\foo}\the\foo\par

\baz=0pt plus -1fil minus 3filll
\scaleglue{1.2}{\baz}{\foo}\the\foo\par

\bye

在此处输入图片描述

当然,像往常一样舍入“错误”。但对于 TeX,1.2 乘以 3 始终等于 3.59999

答案2

整数乘法和除法是可以的。因此你可以这样做:

\newskip\foo
\newskip\bar

\foo=10pt plus 2pt minus 3pt
\bar=\foo\relax
\multiply\bar by 10
\divide\bar by 4
\showthe\bar
\bye

答案3

使用 e-TeXglueexpr将因子从实数转换为整数比率:

\bar=\glueexpr\foo*5/2\relax

这是一个“缩放操作”,先乘法,然后除法。在这种情况下,e-TeX 使用 64 位作为中间值,当然,结果必须在允许的范围内。

答案4

您可以使用\separateskip将跳过寄存器的三个部分分离为三个维度的宏。宏扫描\the寄存器的输出。用法是:

\separateskip\foo to \dimA \dimB \dimC

现在,基础部分存储在 中\dimA,拉伸部分存储在 中\dimB,收缩部分存储在 中\dimC。例如,您可以执行以下操作:

\bar=2.5\dimA plus 4.7\dimB minus1.9\dimC

当然,这里不支持 fil(ll) 单元,因为这些部分存储在普通的 dimen 寄存器中。但您可以编写更复杂的宏,将 fil(ll) 单元也视为练习。

\def\separateskip#1to#2#3#4{\def\tmpa{#3}\def\tmpb{#4}%
   \expandafter\separateskipA\expandafter#2\the#1\end
}
\def\separateskipA#1{\afterassignment\separateskipB #1=}
\def\separateskipB#1\end{\if^#1^\tmpa=0pt \tmpb=0pt \let\next=\relax
   \else \def\next{\separateskipC#1\end}%
   \fi \next
}
\def\separateskipC#1{\if#1\string p\expandafter\separateskipP
   \else \tmpa=0pt \expandafter\separateskipM\fi
}
\def\separateskipP#1 {\afterassignment\separateskipQ \tmpa=}
\def\separateskipQ#1\end{\if^#1^\tmpb=0pt \let\next=\relax
   \else \def\next{\separateskipM#1\end}%
   \fi \next
}
\def\separateskipM#1 {\afterassignment\separateskipN \tmpb=}
\def\separateskipN#1\end{}

\newskip\foo \newskip\bar
\newdimen\dimA  \newdimen\dimB  \newdimen\dimC

\foo=10pt plus3pt minus5pt

\separateskip\foo to \dimA \dimB \dimC

\bar=2.5\dimA plus 4.7\dimB minus1.9\dimC

\message{\the\foo, \the\bar}

\end

相关内容