What are the various units (ex, em, in, pt, bp, dd, pc) expressed in mm?

Here is a variant on Herbert's answer, using \dimexpr instead (inspired from the thread \ifnum for real numbers of comp.text.tex), which allows to do conversions in a purely expandable way. The syntax is \convertto{mm}{1pt} to convert 1pt in mm:

\makeatletter
\def\convertto#1#2{\strip@pt\dimexpr #2*65536/\number\dimexpr 1#1}
\makeatother

The results are not quite the same as with the printlen package, probably due to the fact that \dimexpr performs arithmetic slightly differently from TeX. Here's a table showing all the converted lengths (I omitted sp to avoid arithmetic overflows):

\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}

incipit (2017)

The precise rules how TeX inputs a dimension expressed in a certain unit are commented in these two posts:

  • Why pdf file cannot be reproduced?

  • What value TeX uses as its minimal unit

The underlying thing is that internally all dimensions are integer multiples of sp unit, hence there must be some conversion done. A few salient points:

  • the set of those internal dimensions obtainable from a specification in cm has non empty symmetric difference with the set of those dimensions obtainable from a dimension with in as unit. This is important if one intents to use \ifdim tests. This is a core TeX aspect and will not be changed by any higher level interface for testing dimension equality.

  • when expressing a dimension in a given unit <unit>, the granularity is 1/65536<unit> and using more than five digits after the decimal mark can bring only a one-shot change. But it is hard to guess the borderline: nothing can change beyond 17 decimal digits, but the result obtained from 17 decimal digits is not necessarily the same as the one obtained from rounding these 17 decimal digits to only 5 decimal digits. As this might surprise people I am providing here some examples you can try out:

    • 0.22222pt (from 2/9) gives 14563sp but 0.22222222222222222pt gives 14564sp. One must use 0.22223pt to get also 14654sp.

    • 1.53333pt (from 23/15) gives 100488sp but 1.53333333333333333pt gives 100489sp. One must use 1.53334pt to get also 100489sp.

    Yes, using 0.66667pt is the correct choice, but this is a bit an accidental fact as the two examples above show: sometimes one should round in the opposite direction to get what the full specification with 17digits would have given. (unfortunately it appears I have lost a file where I had tested these things but I remember that my testing revealed that counter-intuitive rounding was needed in roughly 10% of the tested cases, built-up using small fractions like the above ones).

The bigger the dimension unit, the less precise the inner representation. Hence using in is a less precise input method than using cm which is less precise than using pt. For example using em typically means you ave a 10sp granularity, and there is no way to go below that, even with using 17 decimal digits in the expression of the dimension using with em unit. Using pt ensures the minimal 1sp granularity.

Regarding the Didot point, there is a more-detailed examination in a section of the xint manual.

(end of 2017 added contents)


Here is another type of table. It gives the exact irreducible conversion factors between units (em and ex are the special font dependent cases; for them I use \dimexpr but this seems not to be a too good idea, it would perhaps be better to get them from the the suitable \fontdimen parameters).

After the exact table I also give a table with values rounded to five decimal places.

Update: Following a suggestion done in a comment, the tables first. There seems to be something fishy with the em: it seems to be exactly 10pt+1sp and not the more intuitively reasonable 10pt. I would have guessed it should be exactly 10pt in that case with the default CM fonts. But I just tested with \the\fontdimen6\font and it also gave to my surprise 10.00002pt, (compiled with pdftex).

Update: before turning off the internet for a while, I checked the em for bold, slanted and teletype: respectively 11.5pt-4sp, 10pt+1sp and 10.5pt-7sp. Perhaps some font expert could explain what is the mechanism? perhaps an underlying conversion from big points at some stage in the font creation process?

Update: I have played a bit with continued fractions, and a good approximation to 1dd is 107/100pt which is clear also from the decimal expansion in the second table, and a very good fraction approximation to 1dd in millimeters is 44/117 (the previous centered convergent is 3/8=0.375 which is already quite good compared to the exact 0.3760650274... value of 1dd in mm).

Exact conversion table

Rounded to 5 places

\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}

testing the conversion macro

Actually the two approximations, given with 20 places after the decimal mark, for 1em and 1ex, are exact, the denominators are powers of 2, the complete decimal expansion only has zeros after those shown. I still do not quite understand why 1em turns out to be 655361sp and not 655360sp=10pt in the case of the CM font. This 10pt+1sp is strange.


alt text

And TeX's nice arithmetic can be seen .. ;-)

\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}