\documentclass{article}
\begin{document}
\tracingmacros=2
\newlength{\len} \setlength{\len}{1cm} we want to write out \verb$\len$ in cm
\the\len { oops, answer in pt}
\setlength{\len}{0.0352\len}
\the\len { good, now we just need to replace pt with cm}
\def\num#1pt{#1cm}
\num1pt { so far so good}
\def\temp{1pt}
\num\temp { not so hot} 0pt %0pt added to end of line just to prevent error message
\expandafter\num\temp { that works}
\expandafter\num\the\len { but not that} 0pt
\edef\temp{\the\len}
\expandafter\num\temp { okay I'm stuck} 0pt
\makeatletter
\strip@pt\len cm Thank you, that works great!
\makeatother
\end{document}
该文件就是问题所在。
如果你想知道我想要这个做什么,请查看\whereami
查看
http://www.elfsoft2000.com/projects/speaker.pdf
答案1
答案是艾利特解释如何得到你想要的东西,但也值得了解这种方法有什么问题
\def\num#1pt{#1cm}
首先要注意的是\the
是可扩展,您可以在内部确认\edef
\newdimen\mydimen
\edef\demo{\the\mydimen}
\show\demo
给出
> \demo=macro:
->0.0pt.
但这里重要的是,pt
这由两个“其他”(类别代码 12)字符组成,而不是两个“字母”。因此,要去掉字母,我们需要使用正确的类别代码p
和t
。LaTeX 内核定义了\rem@pt
使用
\begingroup
\catcode`P=12
\catcode`T=12
\lowercase{
\def\x{\def\rem@pt##1.##2PT{##1\ifnum##2>\z@.##2\fi}}}
\expandafter\endgroup\x
这个想法是将P
和T
变成“其他”字符,并用于创建小写的“其他”p
和t
。可以使用 e-TeX 设置更清晰的定义:
\makeatletter
\edef\@tempa{%
\def\noexpand\rem@pt##1\detokenize{pt}{##1}%
}
\@tempa
我使用 将其\detokenize
转换p
为t
“其他”字符,但不包含小写字母。
LaTeX 提供了\strip@pt
包装器\rem@pt
,然后可以按照 A.Ellett 所演示的那样使用。
答案2
pt
这个答案涉及到的转换的精度cm
。
包裹printlen
该包使用简单的 TeX 算术,在 dimen 寄存器前面printlen
使用一个因子。0.0351459
e-TeX 的\dimexpr
e-TeX 的 更精确\dimexpr
,因为如果乘法后跟除法,它使用 64 位乘积作为中间值。结果四舍五入为 1/65536,因为 TeX 中的最小单位是1sp
。
包裹fp
包提供了定点运算fp
。它支持从 -999999999999999999999.999999999999999999 到 +9999999999999999999999.9999999999999999999999。这是最精确的方法。句点后面的数字可以减少,因为 TeX 最小单位是1sp
。因此超过七位数字没有多大意义。
其他套餐
- LaTeX3 有一个用于定点运算的模块。
pgf
/TikZ
带有几种方法:\pgfmathparse
,...- 定点运算库
- 浮点单元库
比较
\documentclass{article}
\usepackage[hmargin=1pt]{geometry}
\makeatletter
\usepackage{printlen}
\newcommand*{\PTtoCMprintlen}[1]{%
\begingroup
\uselengthunit{cm}%
\dimen@=#1\relax
\printlength{\dimen@}%
\endgroup
}
\newcommand*{\PTtoCMdimexpr}[1]{%
\strip@pt\dimexpr(#1)*254/7227\relax cm%
}
\usepackage{fp}
\newcommand*{\PTtoCMfp}[1]{%
\begingroup
\dimen@=#1\relax
\FPset{\PTtoCM@tmp}{\number\dimen@}%
\FPmul{\PTtoCM@tmp}{\PTtoCM@tmp}{2.54}%
\FPdiv{\PTtoCM@tmp}{\PTtoCM@tmp}{4736286.72}% 72.27 * 65536
\FPprint{\PTtoCM@tmp}%
cm%
\endgroup
}
\newcommand*{\PTtoCMfpround}[1]{%
\begingroup
\dimen@=#1\relax
\FPset{\PTtoCM@tmp}{\number\dimen@}%
\FPmul{\PTtoCM@tmp}{\PTtoCM@tmp}{2.54}%
\FPdiv{\PTtoCM@tmp}{\PTtoCM@tmp}{4736286.72}% 72.27 * 65536
\FPround{\PTtoCM@tmp}{\PTtoCM@tmp}{7}%
\FPprint{\PTtoCM@tmp}%
cm%
\endgroup
}
\makeatother
\begin{document}
\newcommand*{\test}[1]{%
#1 & \PTtoCMprintlen{#1} & \PTtoCMdimexpr{#1}
& \PTtoCMfp{#1} & \PTtoCMfpround{#1} \\%
}
\begin{tabular}{lllll}
& printlen & dimexpr & fp & fpround \\
\hline
\test{1cm}
\test{\the\maxdimen}
\test{89.3999pt}
\test{1sp}
\end{tabular}
\end{document}
评论:
如果
1cm
分配给长度,则会四舍五入到单位sp
,因此“精确”的结果不是1cm
,因此包的结果fp
更正确。TeX 在其长度或 e-TeX 的情况下打印的最大位数
\dimexpr
针对最小单位进行了优化1sp
。将数字从转换pt
为较大单位后cm
,数字变得太小而无法打印,结果四舍五入为零。
答案3
如果你尝试将存储在中的 LaTeX 内部长度转换pt
为更人类可读格式,那么你可以尝试类似以下操作:
\documentclass{article}
\usepackage[T1]{fontenc}
\usepackage{lmodern}
\makeatletter
\newcommand{\pttocm}[1]{\texttt{\string#1}=\the#1 is approximately \strip@pt\dimexpr0.03514598#1\relax cm}
\makeatother
\begin{document}
\newlength{\triallen}
\setlength{\triallen}{89.3999pt}
\pttocm{\triallen}
\end{document}
或者,正如 @werner 指出的那样,您可以使用该包printlen
,然后
\uselengthunit{cm}
\printlength{\triallen}
关于丢失的空间在您的代码中:这是因为裸的 LaTeX 宏(即后面没有括号的宏)吞噬了下面的空间。
答案4
可以使用lengthconvert
包或直接使用 LaTeX3 函数;第一种方式更具可定制性。
\documentclass{article}
\usepackage{lengthconvert}
\newlength{\len}
\begin{document}
\setlength{\len}{1cm}
\Convert[unit=cm]{\len}
\addtolength{\len}{2.5cm}
\Convert[unit=cm]{\len}
\Convert[unit=cm]{1in}
\Convert[unit=pt,precision=2]{1in}
\ExplSyntaxOn
\dim_to_unit:nn {1in}{1mm}
\ExplSyntaxOff
\end{document}