我想计算两个维度之间的比率并得出无量纲数量,以便在过程中进行进一步计算。我似乎无法做到这一点。具体来说,我遇到了两个奇怪的问题:首先,当我进行任何涉及的计算时\strip@pt
,它都会打印数字。此外,计算出错误的比例,我不确定为什么。
\catcode`@=11
\begingroup
\catcode`P=12
\catcode`T=12
\lowercase{
\def\x{\def\rem@pt##1.##2PT{##1\ifnum##2>\z@.##2\fi}}}
\expandafter\endgroup\x
\def\strip@pt{\expandafter\rem@pt\the}
\def\setdimenzerotofontheightanddepth#1#2{
\dimen0=\fontcharht\font`#1
\advance\dimen0 by \fontchardp\font`#1
\ifx#2
\else
\advance\dimen0 by \fontcharht\font`#2
\advance\dimen0 by \fontchardp\font`#2
\fi
}
\setdimenzerotofontheightanddepth fg
\edef\dimzeroamt{\strip@pt\dimen0}
Dimen0 is: \the\dimen0, Baselineskip is: \the\baselineskip
\dimen1=\baselineskip
Unfortunately it also shows the dimzeroamount when I do the calculation: \divide\dimen1 by \dimzeroamt
The ratio is: \strip@pt\dimen1
The real (manually calculated ratio) is $0.90947\dots$
\catcode`@=12
\bye
答案1
图形包中有划分尺寸的代码:
\documentclass{article}
\usepackage{graphics}
\makeatletter
\begin{document}
\def\setdimenzerotofontheightanddepth#1#2{
\dimen8=\fontcharht\font`#1
\advance\dimen8 by \fontchardp\font`#1
\ifx#2
\else
\advance\dimen8 by \fontcharht\font`#2
\advance\dimen8 by \fontchardp\font`#2
\fi
}
\setdimenzerotofontheightanddepth fg
Dimen8 is: \the\dimen8, Baselineskip is: \the\baselineskip
\Gscale@div\tmp \baselineskip{\dimen8}
gives \tmp
The real (manually calculated ratio) is $0.90947\dots$
\end{document}
答案2
这是一个完全纯文本解决方案。它改编自graphics
包。
\catcode`@=11
\begingroup
\catcode`P=12
\catcode`T=12
\lowercase{
\def\x{\def\rem@pt##1.##2PT{##1\ifnum##2>\z@.##2\fi}}}
\expandafter\endgroup\x
\def\strip@pt{\expandafter\rem@pt\the}
\def\setdimenzerotofontheightanddepth#1#2{
\dimen8=\fontcharht\font`#1
\advance\dimen8 by \fontchardp\font`#1
\ifx#2
\else
\advance\dimen8 by \fontcharht\font`#2
\advance\dimen8 by \fontchardp\font`#2
\fi
}
\setdimenzerotofontheightanddepth fg%
\edef\dimzeroamt{\strip@pt\dimen8 %
}%
\dimen0=\baselineskip%
\count0=65536
\loop%
\ifdim\dimen0<8192\p@%
\dimen0=2\dimen0%
\divide\count0 by 2 %
\repeat
\divide\dimen8\count0
\divide\dimen0\dimen8
\strip@pt\dimen0
%\edef\x{\strip@pt\dimen0}
The real (manually calculated ratio) is $0.90947\dots$%
\catcode`@=12
\bye
答案3
TeX 的语法规则告诉你,你可以
\divide\dimen0 by <number>
其中<number>
是整数。 在您的例子中, 的展开式\dimzeroamt
是13.19443
,因此 TeX 会将其除以\dimen0
13 并打印.19443
。
您可以使用以下方法完成此操作expl3
(也可以使用 Plain TeX):
\input expl3-generic
\ExplSyntaxOn
\cs_new_protected:Nn \ioiooiioio_getfactor:Nnnn
{% #1 is a control sequence, #2 the dimension, #3 and #4 two characters
\tl_set:Nx #1
{
\fp_eval:n
{
\dim_to_fp:n { #2 } /
\dim_to_fp:n
{
\fontcharht\font`#3 + \fontcharht\font`#4
+
\fontchardp\font`#3 + \fontchardp\font`#4
}
}
}
}
\cs_set_eq:NN \getfactor \ioiooiioio_getfactor:Nnnn
\ExplSyntaxOff
\getfactor\test{\baselineskip}{f}{g}
\test
\bye
我不确定您是否想将这些尺寸相加;如果您想使用高度和深度之间的最大值,请将第二条\dim_to_fp:n
命令中的行更改为
\dim_max:nn { \fontcharht\font`#3 } { \fontcharht\font`#4 }
+
\dim_max:nn { \fontchardp\font`#3 } { \fontchardp\font`#4 }
答案4
@wipet 的回答解释了如何使用 e-TeX。使用相同方法的变体:
\makeatletter
\newcommand\SetToRatio[3]{% sets #1 to be the ratio #2/#3, where #2 and #3
% are lengths (registers or expressions).
% The ratio #2/#3 should evaluate to less than 16384 in absolute value to
% avoid arithmetic overflow. It will be computed as fixed point
% number with about 4 or 5 digits after decimal mark.
\edef #1%
{\strip@pt\dimexpr
\numexpr\dimexpr#2\relax*65536/\dimexpr#3\relax\relax sp\relax}%
}
\makeatother
20000
但请注意,这种方法存在缺陷,因为 20000pt
大于 TeX 最大尺寸,所以无法得出结果,即比率 R,因此无法通过 生成\dimexpr
。因此我们不能这样做
\SetToRatio{\foo}{20000sp}{1sp}
尽管论证完全合法,但结果20000
却无法产生。
在我的另一个回答中https://tex.stackexchange.com/a/328894/4686,我编写了一个纯 Plain TeX 宏,它没有这个缺陷,并且比 Graphics 宏更精确。
答案包含最终舍入不同的变体,这里是变体 D。我使用 LaTeX 文档来方便网站访问者进行测试。该宏实际上称为\divdef
,而不是\SetToRatio
。它不使用任何包。
% j'avais fait cela dans https://tex.stackexchange.com/a/328894/4686
% Octobre 2016
\documentclass{article}
\makeatletter
\countdef\ddf@cnta=\z@
\countdef\ddf@cntb=\tw@
\countdef\ddf@cntc=4
\countdef\ddf@cntd=6
% % if used with Plain TeX, un-comment this
% % LaTeX loop or any loop allowing \else\repeat:
%
% \long\def\loop #1\repeat{%
% \def \iterate {#1\relax \expandafter \iterate \fi}\iterate
% \let \iterate \relax }
% \def\divdef #1#2#3{% if using plain tex
\newcommand\divdef [3]{%
% description:
% computes R = #2/#3 as nearest multiple of 1/65536 (ties go to even)
% then define the macro #1 to be the decimal expansion of this up to five digits
% after decimal mark.
\begingroup
\dimen@ #3\relax % denominator
\dimen@ii #2\relax % numerator
\ifdim\dimen@<\z@
\dimen@-\dimen@
\dimen@ii-\dimen@ii
\fi
\ifdim\dimen@ii<\z@
\def\ddf@sgn{-}\dimen@ii-\dimen@ii
\else
\let\ddf@sgn\empty % no \@empty in Plain !
\fi
\ddf@cnta\dimen@ % non negative denominator (we hope non zero...)
\ddf@cntb\dimen@ii % non negative numerator
\divide\ddf@cntb\ddf@cnta % integer part of ratio, will be stored in \ddf@cntd
\ddf@cntd\ddf@cntb
\multiply\ddf@cntb-\ddf@cnta % no overflow possible because TeX's division truncates
\advance\ddf@cntb\dimen@ii % now numerator in \ddf@cntb is < denom
\count@\z@ % will store fractional part as a multiple of sp's
\ifnum\ddf@cntb>\z@
\ifnum\ddf@cnta>32768\relax
\ddf@cnta65536\relax
\loop
\ddf@cntc\dimen@ % denominator
\advance\ddf@cntc-\ddf@cntb
\ifnum\ddf@cntb<\ddf@cntc
\divide\ddf@cnta\tw@
\advance\ddf@cntb\ddf@cntb
\else
\ifnum\ddf@cntb=\ddf@cntc
\divide\ddf@cnta\tw@
\advance\count@\ddf@cnta
\ddf@cnta\z@ % abort the loop here
\else
\advance\count@\ddf@cnta % not same order as in previous branch!
\divide\ddf@cnta\tw@
\ddf@cnta-\ddf@cnta
\advance\ddf@cntc\ddf@cntc
\ddf@cntb\ddf@cntc
\fi
\fi
\ifnum\ddf@cnta=\z@\else % signed quantity: can not do if foo>\z@ ...
\repeat
% it is possible here that \count@ is 65536
% in case of a tie at the last unit the rounding was to even!
\else
% here denom <= 2^15=32768 (=0.5pt), hence 65536num <= 2^31 - 65536
\multiply\ddf@cntb65536\relax
% extra steps to do rounding
\ddf@cntc\ddf@cnta
\divide\ddf@cntc\tw@
\advance\ddf@cntb\ddf@cntc % no overflow possible
\ddf@cntc\ddf@cntb % need to keep copy for later branch
\divide\ddf@cntc\ddf@cnta
\count@\ddf@cntc
\ifodd\ddf@cnta
% odd denom, no tie possible
\else
\multiply\ddf@cntc\ddf@cnta
\ifnum\ddf@cntb=\ddf@cntc
% implement "ties go to even", the rounding was "up"
\ifodd\count@\advance\count@\m@ne\fi
\fi
\fi
% to get \count@ 65536 we would need to have N/D >= 65535.5/65536
% i.e. N/D >= 1 - 1/131072, but N/D<= 1 - 1/D, D<=32768, hence
% despite the rounding this branch always produces \count@ < 65536.
\fi
\fi
\dimen@\count@ sp\relax
% (\the\count@) % debug check
\expandafter\divdef@end\the\dimen@ #1%
}
\begingroup
\catcode`P 12
\catcode`T 12
\lowercase{\gdef\divdef@end #1.#2PT}#3{%
\advance\ddf@cntd #1\relax % almost always #1=0
\ifnum#2>\z@
\edef\x{\endgroup\edef\noexpand#3{\ddf@sgn\the\ddf@cntd.#2}}%
\else
\ddf@cntd\ddf@sgn\ddf@cntd
\edef\x{\endgroup\edef\noexpand#3{\the\ddf@cntd}}%
\fi
\x
}\endgroup
\begin{document}
\ttfamily
\divdef\FOO{20000sp}{1sp}
\meaning\FOO
\divdef\FOO{355pt}{113pt}
\meaning\FOO
\divdef\FOO{1pt}{7pt}
\meaning\FOO
\divdef\FOO{10000pt}{7pt}
\meaning\FOO
\divdef\FOO{1000000000sp}{7sp}
\meaning\FOO
\end{document}
正如您在最后一个例子中所看到的,这超出了其他方法的可能性。