3

I need to use a formula like this:

y = 1.8pt * x + 1.5pt

inside a macro, where x is a scalar macro argument. My idea:

\kern \advance #1\dimexpr1.8pt\relax by \dimexpr1.5pt\relax

This doesn't really work, the \advance command seems wrongly formatted.

  • This is a duplicate of something that is really not easy to find on this site – percusse Sep 27 '13 at 14:28
5

\kern requires a <dimen> after it; it can also be a <skip>, that is coerced to a <dimen> by removing the plus and minus parts.

A <dimen>, according to the TeXbook, is basically either an internal dimen register (for instance \parindent, \dimen2 or any control sequence defined with \newdimen) or an explicit specification <decimal number><unit of measure> (I'll gloss over the finer details).

Also <factor><dimen register> is allowed. So \kern 0.5\parindent is a legal specification.

You can't follow \kern with the instructions to get a length, so an assignment instruction such as \advance is illegal.

However, e-TeX introduced a new possibility: a <dimen> can also be an expression computed with \dimexpr. The syntax is extended so that \dimexpr<dimen expression> can replace an internal dimension in the rules above.

Thus \kern 0.3\dimexpr 1.7pt+\baselineskip\relax (just a silly example) is legal when e-TeX is used, which is the case in all modern TeX distributions when running (pdf)LaTeX, XeLaTeX or LuaLaTeX.

\dimexpr calls can be nested; the \relax at the end is optional and marks the end of the expression, so that TeX won't continue to search for terms belonging to the current expression when it finds \relax (that will vanish).

Therefore you're looking for

\kern \dimexpr 1.5pt + #1\dimexpr 1.8pt\relax\relax

The alternative way without \dimexpr is

\dimen0=1.8pt
\dimen0=#1\dimen0
\advance\dimen0 by 1.5pt
\kern\dimen0

using the scratch register \dimen0, or with the “official” LaTeX commands \setlength and \addtolength. For such a computation, it's not necessary to allocate a new register, but it doesn't hurt.

What's the difference between the two approaches? The \dimexpr way is certainly more flexible; but remind that division with \divide truncates, while \dimexpr(dimen expression)/<integer>\relax rounds. This might be a factor in some computation (but this is more relevant in \numexpr, because dimensions are actually integer multiples of scaled points, so the rounding happens at the scaled point level). Indeed e-TeX provides \numexpr, \dimexpr, \glueexpr and \muexpr to operate on numbers, dimensions, glues and muglues.


By the way, \advance must be followed by an internal register name (\count, \dimen, \skip or \muskip type), so \advance\dimexpr... is illegal also with e-TeX, which would balk with

! You can't use `\dimexpr' after \advance.
  • Thanks for the long explanation, I know too little about "registers" and such. Normally working with general purpose statically typed programming languages, things like R and LaTeX will clearly remain a mystery to me till I die. – Emit Taste Sep 28 '13 at 13:00
1

The following works:

\kern \dimexpr 1.5pt + #1\dimexpr 1.8pt\relax\relax
0

Old school:

\setlength(\y}{1.8pt}
\setlength{\y}{#1\y}
\addtolength{\y}{1.5pt}

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.