25

I have probably formulated the question wrong, as I don't know the Tex internals - but this is what I mean; consider this example:

\newcommand{\myNum}{2}
\newlength{\myLength}
\setlength{\myLength}{\myNum cm}

Here, I'd consider \myNum to represent a 'numeric variable', and \myLength a Tex length (i.e. a number and a unit); and so I'd consider the above example a "conversion" from numeric to length "variable".

Is it possible to do the other way around? I.e. if \myLength is given to be 2 cm, is there a command that will "get"/"extract" the numeric value only? I'd imagine doing something like this (pseudocode):

\newcommand{\myNum}{\getlength{\myLength}}

... after which, \myNum would have value "2" ...

Does anything like this exist?

EDIT: I guess I need something similar to \the which is for counters ... ?!

| improve this question | | | | |
  • 3
    \the\myLength gives you the dimension, I don't know how you'd extract just the number... If you wanted to do something like this, I expect the calc package might be useful. Or possibly this package – Seamus Apr 5 '11 at 10:53
  • Thanks for noting that, @Seamus - I was not aware \the could be applied to lengths too (try searching for "latex \the", hehe :) ); \theMyLength indeed prints the length, but seemingly in pt units. – sdaau Apr 5 '11 at 10:56
21

You can remove the pt unit from the length using \strip@pt as shown below. I you want the number in cm you would have to convert it by yourself.

\documentclass{article}

\makeatletter
\newcommand*{\getlength}[1]{\strip@pt#1}
% Or rounded back to `cm` (there will be some rounding errors!)
%\newcommand*{\getlength}[1]{\strip@pt\dimexpr0.035146\dimexpr#1\relax\relax}

\makeatother

\begin{document}

Test: \getlength{\textwidth}  % Result: 345

\end{document}

Another alternative which is more flexible and also allows you to store the resulting number in a macro is to use pgfmath (pgf package). It also allows you to easily convert the number to cm:

\documentclass{article}

\usepackage{pgf}
\newcommand*{\getlength}[2]{%
   \pgfmathsetmacro#1{#2}%  Result in `pt`
   % Or:
   %\pgfmathsetmacro#1{0.0351459804*#2}%  Result in `cm`
}

\begin{document}

\getlength{\myNum}{\textwidth}

Test: \myNum % Result: 345.0

\end{document}

There is also the round( ) function for pgfmath which allows you to round the number, e.g. to two fractional digits. The trick is to multiple it with 100 before the rounding and divide it afterwards by 100.

\documentclass{article}

\usepackage{pgf}
\newcommand*{\getlength}[2]{%
   % Convert to `cm` and round to two fractional digits:
   \pgfmathsetmacro#1{round(3.51459804*#2)/100.0}%
}

\begin{document}

\setlength{\textwidth}{2.123cm}
\getlength{\myNum}{\textwidth}

Test: \myNum% Gives 2.12

\setlength{\textwidth}{2cm}
\getlength{\myNum}{\textwidth}

Test: \myNum% Gives 2.0

\end{document}

The fractional part (like .0) can be avoided by using \pgfmathtruncatemacro instead of \pgfmathsetmacro, but I don't think you need that.

| improve this answer | | | | |
  • Fantastic - thanks for the fast response, @Martin Scharrer! – sdaau Apr 5 '11 at 10:57
  • 3
    @sdaau: Minor note about the pgfmath round function: I wouldn't rely on the "multiply by 100, round, divide by 100" method. I tried it recently and found that the accuracy was quite poor. – Andrew Stacey Apr 5 '11 at 11:16
  • 2
    Thanks @Andrew. An alternative would be to truncate the digits instead: \def\twofracdigits#1.#2#3#4\relax{#1.#2#3} \newcommand*{\getlength}[2]{% \pgfmathsetmacro#1{0.0351459804*#2}% \edef#1{\expandafter\twofracdigits#1\empty\empty\relax}% }. However the OP might not need this at all. – Martin Scharrer Apr 5 '11 at 11:40
  • 4
    @sdaau: I've just tried the example where I got the inaccuracy and I can't reproduce it. So I think I'd like to downgrade my warning a bit to just: "be careful". However, I would recommend using the \pgfmathprintnumber command (see the pgf manual for more details) instead of the "multiply, round, divide" cycle. – Andrew Stacey Apr 5 '11 at 11:40
  • 1
    @Martin: I think it's new in 2.10. – Andrew Stacey Apr 5 '11 at 11:42
12

An alternative to Martin's approach is to use TeX's \number primitive, which will give you the underlying integer value in sp

\documentclass{article}

\newcommand*\getlength[1]{\number#1}

\begin{document}

Test: \getlength{\textwidth}

\end{document}

(TeX does everything in integers, more or less, so lengths are actually stored in sp, which are tiny length units. Everything else is an integer multiple of a value in sp.)

| improve this answer | | | | |
  • 3
    Damn: I was 49 seconds slower. – Bruno Le Floch Apr 5 '11 at 11:03
  • 1
    @Bruno: Ah well :-) – Joseph Wright Apr 5 '11 at 11:04
  • Thanks for that @Bruno Le Floch & @Joseph Wright - great to know that primitive! (Also thanks for the note on internal storage in Tex) – sdaau Apr 5 '11 at 11:10
  • 7
    +1 Just as a reference: 65536 sp = 1 pt – Martin Scharrer Apr 5 '11 at 11:24
  • 2
    And if needed you can use the fp package to do calculations with floating point numbers. – Bruno Le Floch Apr 5 '11 at 17:20
1

One can use xfp:

\documentclass{article}
\usepackage{xfp}

\NewExpandableDocumentCommand{\getlengthnumber}{O{pt}m}{%
  % #1 (optional, default pt), #2 = length
  \fpeval{(#2)/(1#1)}%
}

\begin{document}

\getlengthnumber{\textwidth}

\getlengthnumber[cm]{\textwidth}

\getlengthnumber[cm]{1in}

\getlengthnumber[sp]{1pt}

\end{document}

The big advantage over the pgf methods is that this is fully expandable.

enter image description here

| improve this answer | | | | |
0

Here I would like to provide a simple solution with pgf

% !Mode:: "TeX:UTF-8"
\documentclass{article}
\usepackage{pgf}

\begin{document}
\noindent
\the\textwidth \\
\pgfmathparse{\textwidth}
\pgfmathresult \\
\end{document}

where \the\textwidth prints the length with units, while \pgfmathparse returns \textwidth without unit to \pgfmathresult

length

there are many more functions to choose from section Mathematical Expressions in pgf manual.

| improve this answer | | | | |
  • Did you try \usepackage{xfp} and then \fpeval(\textwidth}? By the way, your method is already covered in Martin Scharrer's answer. – egreg May 2 at 9:03
  • @egreg Thanks, \fpeval(\textwidth} is also a nice solution. As for the second point, although we both used pgf, he used \pgfmathsetmacro and I used \pgfmathparse. – zyy May 2 at 13:49

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.