11

How do I divide two lengths and get a length out?

\documentclass{article}
\newlength\A
\newlength\B
\newlength\C
\setlength\A{10pt}
\setlength\B{5pt}
\setlength\C{\dimexpr\A/\B\relax}
\begin{document}
\the\C
\end{document}

The result is 0.00003pt, while I want the result to be 10/5=2pt.

  • How can you get a length from the ratio of two lengths? The ratio between 2 km and 1 km is exactly the same thing as the ratio between 10 pt and 5pt. What would you use this ratio for? – egreg May 28 '17 at 9:56
  • @egreg: I have increased the size of my \paperwidth by a factor given by \setlength\PPTresizept{\onept*\ratio{\newpaperwidth}{\paperwidth}}. I then do \newcommand\PPTresize{\getlength{\PPTresizept}} to be able to use this factor when I want to resize a rectangle (to maintain the same ratio with the total \paperwidth) in tikz using: \fill (0,0) rectangle (100pt/\PPTresize,50pt/\PPTresize);. Perhaps there is a better way, but Joseph Wright's solution works. – Carucel May 28 '17 at 10:38
13

You can't divide one dimension by another and get a dimension: the units would cancel. You need the ratio of the two multiplied by the numerator. For example

\documentclass{article}
\usepackage{calc}
\newlength\A
\newlength\B
\newlength\C
\setlength\A{10pt}
\setlength\B{5pt}
\setlength\C{\A*\ratio{\A}{\B}}
\begin{document}
\the\C
\end{document}

takes the ratio and multiplies it by \A, whereas

\documentclass{article}
\usepackage{calc}
\newlength\A
\newlength\B
\newlength\C
\setlength\A{10pt}
\setlength\B{5pt}
\setlength\C{1pt * \ratio{\A}{\B} }
\begin{document}
\the\C
\end{document}

gives the 'ratio as a length' (not quite sure that makes sense, but it's what the question asks!).

| improve this answer | |
  • 1
    Thank you! I used your solution to do \newlength{\onept}\setlength{\onept}{1pt} and \setlength\C{\onept*\ratio{\A}{\B}}, which gives the correct value of 2pt. – Carucel May 28 '17 at 6:36
  • This calculates A*A/B instead of A/B. Therefore you should use \setlength\C{1pt*\ratio{\A}{\B}}, if the unit is pt. – dexteritas Jul 25 '19 at 13:03
  • @dexteritas I've adjusted the answer: I'm not really sure what the questionner was doing ... – Joseph Wright Jul 25 '19 at 13:21
8

You don't need calc package:

\documentclass{article}
\newlength\A
\newlength\B
\newlength\C
\setlength\A{10pt}
\setlength\B{5pt}
\setlength\C{\dimexpr \numexpr \A * \A / \B \relax sp\relax}
\begin{document}
\the\C
\end{document}

produces 20.0pt.

I include the \relax for clarity, they terminate the expressions and get swallowed. Depending how \setlength is coded (not checked) the second one may be superfluous. The first one is superfluous because the letter s terminates the \numexpr with no error.

Explanations:

  • inside \numexpr a dimension is converted into an integer representing its value in "scaled points" (1sp = 1/65536pt). This is in fact the TeX internal representation of a length (or rather the \dimen part of it, discarding glue components; the LaTeX lengths are actually skips).

  • inside \numexpr you are allowed to do in temporary doubled precision a so-called "scaling" operation i.e. (u times v) divided by w. No overflow will be raised by the first operation, even though the intermediate product exceeds the 2^31-1 TeX bound for numbers.

  • finally we convert back to dimen by using explicitely unit sp.

Related notes:

  • the graphics package internally has some macro to divide dimensions,

  • in a another answer of mine which I will will try to find I provided a TeX macro (non-expandable) not using e-TeX doing this division with higher precision than the graphics version.

Related:

see https://tex.stackexchange.com/a/328894/4686, particularly the \divdef macro from Part D for non-eTeX macro reliably dividing lengths and producing the result as a fixed point number with 4 or 5 decimal digits (after decimal mark).

This is not using any extra package.

| improve this answer | |

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.