如何确定中不同单位(测量1ex
、1em
、1in
、1pt
、1bp
、1dd
)的长度?1pc
mm
答案1
以下是 Herbert 答案的一个变体,使用\dimexpr
(灵感来自主题\ifnum 表示实数\convertto{mm}{1pt}
comp.text.tex 的转换),它允许以纯粹可扩展的方式进行转换。语法1pt
如下mm
:
\makeatletter
\def\convertto#1#2{\strip@pt\dimexpr #2*65536/\number\dimexpr 1#1}
\makeatother
结果与打印长度包,可能是因为其\dimexpr
执行的算术与 TeX 略有不同。下面是显示所有转换长度的表格(我省略了sp
以避免算术溢出):
\documentclass[a4paper]{article}
\usepackage{array}
\usepackage[hmargin=2cm]{geometry}
\makeatletter
%http://groups.google.com/group/comp.text.tex/msg/7e812e5d6e67fcc5
\def\convertto#1#2{\strip@pt\dimexpr #2*65536/\number\dimexpr 1#1}
\makeatother
\begin{document}
\begin{center}\begin{tabular}
{>{\def\colunit{pt}}l<{\convertto{\rowunit}{1\colunit}}
>{\def\colunit{mm}}l<{\convertto{\rowunit}{1\colunit}}
>{\def\colunit{cm}}l<{\convertto{\rowunit}{1\colunit}}
>{\def\colunit{ex}}l<{\convertto{\rowunit}{1\colunit}}
>{\def\colunit{em}}l<{\convertto{\rowunit}{1\colunit}}
>{\def\colunit{bp}}l<{\convertto{\rowunit}{1\colunit}}
>{\def\colunit{dd}}l<{\convertto{\rowunit}{1\colunit}}
>{\def\colunit{pc}}l<{\convertto{\rowunit}{1\colunit}}
>{\def\colunit{in}}l<{\convertto{\rowunit}{1\colunit}}
>{\bfseries}l}
\multicolumn{1}{l}{\bfseries 1pt} & \multicolumn{1}{l}{\bfseries 1mm} & \multicolumn{1}{l}{\bfseries 1cm} & \multicolumn{1}{l}{\bfseries 1ex} & \multicolumn{1}{l}{\bfseries 1em} & \multicolumn{1}{l}{\bfseries 1bp} & \multicolumn{1}{l}{\bfseries 1dd} & \multicolumn{1}{l}{\bfseries 1pc} & \multicolumn{1}{l}{\bfseries 1in} & \\
\gdef\rowunit{pt} & & & & & & & & & \rowunit\\
\gdef\rowunit{mm} & & & & & & & & & \rowunit\\
\gdef\rowunit{cm} & & & & & & & & & \rowunit\\
\gdef\rowunit{ex} & & & & & & & & & \rowunit\\
\gdef\rowunit{em} & & & & & & & & & \rowunit\\
\gdef\rowunit{bp} & & & & & & & & & \rowunit\\
\gdef\rowunit{dd} & & & & & & & & & \rowunit\\
\gdef\rowunit{pc} & & & & & & & & & \rowunit\\
\gdef\rowunit{in} & & & & & & & & & \rowunit\\
\end{tabular}\end{center}
\end{document}
答案2
开始 (2017)
TeX 输入以特定单位表示的尺寸的精确规则在这两篇文章中有评论:
根本原因是,内部所有维度都是单位的整数倍sp
,因此必须进行一些转换。以下是一些要点:
从规范中获取的内部维度集
cm
与从以 为单位的维度中获取的内部维度集具有非空对称差异in
。如果打算使用\ifdim
测试,这一点很重要。这是核心 TeX 方面,不会被任何用于测试维度相等性的更高级别接口更改。当用给定单位表示维度时
<unit>
,粒度为1/65536<unit>
,使用小数点后超过五位数字只能带来一次性变化。但很难猜测边界:超过 17 位小数就不会有什么变化,但从 17 位小数获得的结果不一定与从四舍五入这 17 位小数变为只有 5 位小数。这可能会让人感到惊讶,我在这里提供了一些您可以尝试的示例:0.22222pt(来自 2/9)给出 14563sp 但 0.22222222222222222pt 给出 14564sp。必须使用 0.22223pt 才能获得 14654sp。
1.53333pt(来自 23/15)给出 100488sp 但 1.533333333333333333pt 给出 100489sp。必须使用 1.53334pt 才能获得 100489sp。
是的,使用 0.66667pt 是正确的选择,但这有点偶然,正如上面的两个例子所示:有时应该朝相反的方向舍入才能得到 17 位数字的完整规范所给出的结果。(不幸的是,我似乎丢失了一个测试过这些内容的文件,但我记得我的测试表明,在大约的
10%
测试案例中需要反直觉的舍入,使用像上面那样的小分数构建)。
维度单位越大,内部表示越不精确。因此,使用in
是一种精度低于使用的输入方法,而cm
使用 的精度又低于使用pt
。例如,使用em
通常意味着您有一个10sp
粒度,并且即使在使用 单位的维度表达式中使用 17 位小数,也无法低于该粒度em
。使用pt
可确保最小1sp
粒度。
关于 Didot 点,在信特手动的。
(2017年底添加内容)
这是另一种类型的表格。它给出了单位之间的精确的不可约换算因子(em
和ex
是特殊的字体相关情况;对于它们我使用\dimexpr
但这似乎不是一个好主意,也许最好从合适的参数中获取它们\fontdimen
)。
在精确的表格之后,我还给出了一个将数值四舍五入到小数点后五位的表格。
更新:根据评论中的建议,首先是表格。 似乎有些可疑em
:它似乎完全正确10pt+1sp
,而不是更直观合理的10pt
。我猜想10pt
在这种情况下,使用默认的 CM 字体应该完全正确。但我刚刚用 进行了测试\the\fontdimen6\font
,它也让我感到惊讶10.00002pt
,(用 pdftex 编译)。
更新:在关闭互联网一段时间之前,我检查了em
粗体、倾斜和电传打字机:分别是11.5pt-4sp
和10pt+1sp
。10.5pt-7sp
也许一些字体专家可以解释一下这种机制是什么?也许是在字体创建过程的某个阶段从大点进行的底层转换?
更新:我对连分数进行了一些研究, 的一个很好的近似值1dd
是,107/100pt
这从第二个表中的小数展开式中也可以清楚地看出,而 (以1dd
毫米为单位)的 的一个非常好的分数近似值是44/117
(先前的中心收敛是,与中的3/8=0.375
精确值相比已经相当不错了)。0.3760650274...
1dd
mm
\documentclass{article}
\usepackage{xintfrac}
% http://www.ctan.org/tex-archive/macros/generic/xint
% This code was compiled with the version 1.06a of the xint
% bundle dated 2013/05/09, which should appear soon on CTAN.
% The current CTAN version 1.06 should be also OK for this.
\usepackage{array}
\usepackage[hmargin=.5cm]{geometry}
% Conversions to the basic dimension, chosen to be the centimeter
% Base dimension: 1cm
\def\onecm {1}
\def\onemm {1/10}
\def\onein {2.54}
%% \def\onept {\xintMul {1/72.27}{\onein}}
%% simpler:
\def\onept {2.54/72.27}
%% \def\onebp {\xintMul {1/72}{\onein}}
%% simpler:
\def\onebp {2.54/72}
\def\onepc {\xintMul {12}{\onept}}
\def\oneex {\xintMul {\the\numexpr\dimexpr 1ex\relax\relax}{\onesp}}
\def\oneem {\xintMul {\the\numexpr\dimexpr 1em\relax\relax}{\onesp}}
\def\onedd {\xintMul {1238/1157}{\onept}}
% 1157 dd = 1238 pt I take this conversion factor from the TeXBook
% Wikipedia has other conversion factors, but of course here we
% have to do it the TeX way.
\def\onecc {\xintMul {12}{\onedd}}
\def\onesp {\xintMul {1/65536}{\onept}}
% Routines with delimited arguments, the good old TeX way
% (completely expandable)
\makeatletter
% exact conversion to an irreducible fraction:
% example: \convertexactly 126.2772pt\to {bp}
% and `pt' may be a macro expanding to it.
% idem for {bp} which may be a macro expanding to bp
\def\convertexactly #1\to #2%
{\xintIrr{\convertexactly@ #1\to {#2}}}%
% Variant with rounding at a number of decimal places
% given by first argument.
\def\convertwithrounding #1#2\to #3%
{\xintRound {#1}{\convertexactly@ #2\to {#3}}}%
% routines doing the job:
\def\convertexactly@ #1\to
{%
\romannumeral0%
\expandafter\expandafter\expandafter
\convertexactly@a
\xintReverseOrder {#1}\Z
}%
\def\convertexactly@a #1%
{%
\ifcat\noexpand #1\relax
\expandafter \convertexactly@b
\else
\expandafter \convertexactly@c
\fi #1%
}%
\def\convertexactly@b #1#2\Z #3%
{%
\xintdiv {\xintMul {\xintReverseOrder{#2}}{\csname one#1\endcsname}}
{\csname one#3\endcsname}%
}%
\def\convertexactly@c #1#2#3\Z #4%
{%
\xintdiv {\xintMul {\xintReverseOrder{#3}}{\csname one#2#1\endcsname}}
{\csname one#4\endcsname}%
}%
\makeatother
\def\bigstrut {\vbox to 24pt{}\vbox to 12pt{}}%
\begin{document}
Testing:
72.27pt is exactly \convertexactly 72.27pt\to {bp}bp
1/2.54in is exactly \convertexactly 1/2.54in\to {mm}mm
10pt is exactly (for this font) \convertexactly 10pt\to {ex}ex,
or approximately \convertwithrounding{20}10pt\to {ex}ex
10pt is exactly (for this font) \convertexactly 10pt\to {em}em,
or approximately \convertwithrounding{20}10pt\to {em}em
1em is exactly (for this font) \convertexactly
1em\to {pt}pt, or approximately
\convertwithrounding{20}1em\to {pt}pt.
And indeed
\verb+\the\dimexpr 1em\relax+ gives \the\dimexpr 1em\relax{} and
\verb+\the\fontdimen6\font+ gives \the\fontdimen6\font
1ex is exactly (for this font) \convertexactly 1ex\to {pt}pt, or approximately
\convertwithrounding{20}1ex\to {pt}pt.
And indeed
\verb+\the\dimexpr 1ex\relax+ gives \the\dimexpr 1ex\relax.
\def\tableentry{$\displaystyle\xintFrac{\convertexactly 1\colunit\to\rowunit}$\bigstrut}
\begin{center}\begin{tabular}
{>{\def\colunit{pt}}l<{\tableentry}
>{\def\colunit{mm}}l<{\tableentry}
>{\def\colunit{cm}}l<{\tableentry}
>{\def\colunit{ex}}l<{\tableentry}
>{\def\colunit{em}}l<{\tableentry}
>{\def\colunit{bp}}l<{\tableentry}
>{\def\colunit{dd}}l<{\tableentry}
>{\def\colunit{pc}}l<{\tableentry}
>{\def\colunit{in}}l<{\tableentry}
>{\bfseries}l}
\multicolumn{1}{l}{\bfseries 1pt} & \multicolumn{1}{l}{\bfseries 1mm} &
\multicolumn{1}{l}{\bfseries 1cm} & \multicolumn{1}{l}{\bfseries 1ex} &
\multicolumn{1}{l}{\bfseries 1em} & \multicolumn{1}{l}{\bfseries 1bp} &
\multicolumn{1}{l}{\bfseries 1dd} & \multicolumn{1}{l}{\bfseries 1pc} &
\multicolumn{1}{l}{\bfseries 1in} & \\
\gdef\rowunit{pt} & & & & & & & & & \rowunit\\
\gdef\rowunit{mm} & & & & & & & & & \rowunit\\
\gdef\rowunit{cm} & & & & & & & & & \rowunit\\
\gdef\rowunit{ex} & & & & & & & & & \rowunit\\
\gdef\rowunit{em} & & & & & & & & & \rowunit\\
\gdef\rowunit{bp} & & & & & & & & & \rowunit\\
\gdef\rowunit{dd} & & & & & & & & & \rowunit\\
\gdef\rowunit{pc} & & & & & & & & & \rowunit\\
\gdef\rowunit{in} & & & & & & & & & \rowunit\\
\end{tabular}\end{center}
\clearpage
\def\tableentry{\convertwithrounding {5}1\colunit\to\rowunit}
\begin{center}\begin{tabular}
{>{\def\colunit{pt}}l<{\tableentry}
>{\def\colunit{mm}}l<{\tableentry}
>{\def\colunit{cm}}l<{\tableentry}
>{\def\colunit{ex}}l<{\tableentry}
>{\def\colunit{em}}l<{\tableentry}
>{\def\colunit{bp}}l<{\tableentry}
>{\def\colunit{dd}}l<{\tableentry}
>{\def\colunit{pc}}l<{\tableentry}
>{\def\colunit{in}}l<{\tableentry}
>{\bfseries}l}
\multicolumn{1}{l}{\bfseries 1pt} & \multicolumn{1}{l}{\bfseries 1mm} &
\multicolumn{1}{l}{\bfseries 1cm} & \multicolumn{1}{l}{\bfseries 1ex} &
\multicolumn{1}{l}{\bfseries 1em} & \multicolumn{1}{l}{\bfseries 1bp} &
\multicolumn{1}{l}{\bfseries 1dd} & \multicolumn{1}{l}{\bfseries 1pc} &
\multicolumn{1}{l}{\bfseries 1in} & \\
\gdef\rowunit{pt} & & & & & & & & & \rowunit\\
\gdef\rowunit{mm} & & & & & & & & & \rowunit\\
\gdef\rowunit{cm} & & & & & & & & & \rowunit\\
\gdef\rowunit{ex} & & & & & & & & & \rowunit\\
\gdef\rowunit{em} & & & & & & & & & \rowunit\\
\gdef\rowunit{bp} & & & & & & & & & \rowunit\\
\gdef\rowunit{dd} & & & & & & & & & \rowunit\\
\gdef\rowunit{pc} & & & & & & & & & \rowunit\\
\gdef\rowunit{in} & & & & & & & & & \rowunit\\
\end{tabular}\end{center}
\end{document}
事实上近似值20
,小数点后有1 位,对于1em
和1ex
,是精确的,分母是 2 的幂,完整的十进制展开式中只有显示的后面有零。我仍然不太明白为什么在 CM 字体的情况下1em
结果是655361sp
而不是。这很奇怪。655360sp=10pt
10pt+1sp
答案3
并且可以看到 TeX 的优秀算法.. ;-)
\documentclass{article}
\usepackage{printlen}
\parindent=0pt
\newlength\Length \Length=1cm
\begin{document}
\tabular{p{2cm}p{2cm}}
\mbox{--- 1cm ---}
\uselengthunit{cm}\printlength{\Length}\
\uselengthunit{mm}\printlength{\Length}\
\uselengthunit{in}\printlength{\Length}\
\uselengthunit{pt}\printlength{\Length}\
\uselengthunit{bp}\printlength{\Length}\
\uselengthunit{sp}\printlength{\Length}\
\uselengthunit{pc}\printlength{\Length}\
&
\mbox{--- 1em ---}
\Length=1em
\uselengthunit{cm}\printlength{\Length}\
\uselengthunit{mm}\printlength{\Length}\
\uselengthunit{in}\printlength{\Length}\
\uselengthunit{pt}\printlength{\Length}\
\uselengthunit{bp}\printlength{\Length}\
\uselengthunit{sp}\printlength{\Length}\
\uselengthunit{pc}\printlength{\Length}
\endtabular
\end{document}
答案4
与 Philippe Goutet 的相同,但使用fp
LaTeX3 模块;然而命令的语法\convertto
不同:
\convertto{1in}{pt}
返回72.26999
,仅数字。使用 ,\convertto*{1in}{pt}
我们将获得72.26999pt
,带单位。
\documentclass[a4paper]{article}
\usepackage{array}
\usepackage[hmargin=2cm]{geometry}
\usepackage{xparse}
\ExplSyntaxOn
\NewExpandableDocumentCommand{\convertto}{smm}
{
\egreg_convertto:nn {#2}{#3}
\IfBooleanT{#1}{#2}
}
\cs_new:Npn \egreg_convertto:nn #1 #2
{
\fp_eval:n { round( \dim_to_decimal:n { #1 } / \dim_to_decimal:n {1#2} , 5 ) }
}
\ExplSyntaxOff
\begin{document}
\begin{center}\begin{tabular}
{>{\def\colunit{pt}}l<{\convertto{1\colunit}{\rowunit}}
>{\def\colunit{mm}}l<{\convertto{1\colunit}{\rowunit}}
>{\def\colunit{cm}}l<{\convertto{1\colunit}{\rowunit}}
>{\def\colunit{ex}}l<{\convertto{1\colunit}{\rowunit}}
>{\def\colunit{em}}l<{\convertto{1\colunit}{\rowunit}}
>{\def\colunit{bp}}l<{\convertto{1\colunit}{\rowunit}}
>{\def\colunit{dd}}l<{\convertto{1\colunit}{\rowunit}}
>{\def\colunit{pc}}l<{\convertto{1\colunit}{\rowunit}}
>{\def\colunit{in}}l<{\convertto{1\colunit}{\rowunit}}
>{\bfseries}l}
\multicolumn{1}{l}{\bfseries 1pt} & \multicolumn{1}{l}{\bfseries 1mm} &
\multicolumn{1}{l}{\bfseries 1cm} & \multicolumn{1}{l}{\bfseries 1ex} &
\multicolumn{1}{l}{\bfseries 1em} & \multicolumn{1}{l}{\bfseries 1bp} &
\multicolumn{1}{l}{\bfseries 1dd} & \multicolumn{1}{l}{\bfseries 1pc} &
\multicolumn{1}{l}{\bfseries 1in} & \\
\gdef\rowunit{pt} & & & & & & & & & \rowunit\\
\gdef\rowunit{mm} & & & & & & & & & \rowunit\\
\gdef\rowunit{cm} & & & & & & & & & \rowunit\\
\gdef\rowunit{ex} & & & & & & & & & \rowunit\\
\gdef\rowunit{em} & & & & & & & & & \rowunit\\
\gdef\rowunit{bp} & & & & & & & & & \rowunit\\
\gdef\rowunit{dd} & & & & & & & & & \rowunit\\
\gdef\rowunit{pc} & & & & & & & & & \rowunit\\
\gdef\rowunit{in} & & & & & & & & & \rowunit\\
\end{tabular}\end{center}
\end{document}
\convertto
和均可\convertto*
在可扩展的上下文中使用。
同一张表,但siunitx
(与已建的表进行比较)。需要事先准备好表的主体。
\documentclass[a4paper]{article}
\usepackage{siunitx,array}
\usepackage[hmargin=1cm]{geometry}
\usepackage{xparse}
\ExplSyntaxOn
\seq_new:N \g_egreg_convertto_units_seq
\seq_new:N \l_egreg_convertto_temp_seq
\tl_new:N \l_egreg_convertto_body_tl
\seq_gset_from_clist:Nn \g_egreg_convertto_units_seq
{
pt, mm, cm, ex, em, bp, dd, pc, in
}
\cs_new_protected:Nn \__egreg_convertto_maketable:
{
\seq_map_inline:Nn \g_egreg_convertto_units_seq
{
\seq_clear:N \l_egreg_convertto_temp_seq
\seq_map_inline:Nn \g_egreg_convertto_units_seq
{
\seq_put_right:Nx \l_egreg_convertto_temp_seq { \egreg_convertto:nn { 1####1 } { ##1 } }
}
\tl_put_right:Nx \l_egreg_convertto_body_tl
{
\seq_use:Nn \l_egreg_convertto_temp_seq { & } & \exp_not:n { \textbf{##1} \\ }
}
}
\seq_set_map:NNn \l_egreg_convertto_temp_seq \g_egreg_convertto_units_seq { {\exp_not:N \textbf{1\,##1}} }
}
\NewDocumentCommand{\maketable}{}
{
\__egreg_convertto_maketable:
\begin{tabular}{*{\seq_count:N \g_egreg_convertto_units_seq}{S[table-format=2.5]}l}
\seq_use:Nn \l_egreg_convertto_temp_seq { & } \\
\l_egreg_convertto_body_tl
\end{tabular}
}
\NewExpandableDocumentCommand{\convertto}{smm}
{
\egreg_convertto:nn {#2}{#3}
\IfBooleanT{#1}{#2}
}
\cs_new:Npn \egreg_convertto:nn #1 #2
{
\fp_eval:n { round( \dim_to_decimal:n { #1 } / \dim_to_decimal:n {1#2} , 5 ) }
}
\ExplSyntaxOff
\begin{document}
\begin{center}
\sisetup{group-digits=false}
\maketable
\end{center}
\begin{center}
\begin{tabular}
{>{\def\colunit{pt}}l<{\convertto{1\colunit}{\rowunit}}
>{\def\colunit{mm}}l<{\convertto{1\colunit}{\rowunit}}
>{\def\colunit{cm}}l<{\convertto{1\colunit}{\rowunit}}
>{\def\colunit{ex}}l<{\convertto{1\colunit}{\rowunit}}
>{\def\colunit{em}}l<{\convertto{1\colunit}{\rowunit}}
>{\def\colunit{bp}}l<{\convertto{1\colunit}{\rowunit}}
>{\def\colunit{dd}}l<{\convertto{1\colunit}{\rowunit}}
>{\def\colunit{pc}}l<{\convertto{1\colunit}{\rowunit}}
>{\def\colunit{in}}l<{\convertto{1\colunit}{\rowunit}}
>{\bfseries}l}
\multicolumn{1}{l}{\bfseries 1pt} & \multicolumn{1}{l}{\bfseries 1mm} &
\multicolumn{1}{l}{\bfseries 1cm} & \multicolumn{1}{l}{\bfseries 1ex} &
\multicolumn{1}{l}{\bfseries 1em} & \multicolumn{1}{l}{\bfseries 1bp} &
\multicolumn{1}{l}{\bfseries 1dd} & \multicolumn{1}{l}{\bfseries 1pc} &
\multicolumn{1}{l}{\bfseries 1in} & \\
\gdef\rowunit{pt} & & & & & & & & & \rowunit\\
\gdef\rowunit{mm} & & & & & & & & & \rowunit\\
\gdef\rowunit{cm} & & & & & & & & & \rowunit\\
\gdef\rowunit{ex} & & & & & & & & & \rowunit\\
\gdef\rowunit{em} & & & & & & & & & \rowunit\\
\gdef\rowunit{bp} & & & & & & & & & \rowunit\\
\gdef\rowunit{dd} & & & & & & & & & \rowunit\\
\gdef\rowunit{pc} & & & & & & & & & \rowunit\\
\gdef\rowunit{in} & & & & & & & & & \rowunit\\
\end{tabular}\end{center}
\end{document}