是否有可能在 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