About
Shop
LaTeX
Software
Books
Gallery
News
Contact
Blog
Settings
Account
Latest news 2024-12-13: Ebook sale (12th December 2024 – 1st January 2025): cybercrime fiction short stories Unsocial Media and Smile for the Camera free; crime fiction short story The Briefcase free; short story noir crime fiction I’ve Heard the Mermaid Sing free; crime fiction novel The Private Enemy US$1.99; illustrated children’s story The Foolish Hedgehog US$0.99.


2.1.3 Arithmetic

TeX count registers only allow integer values. Even the registers that store dimensions (such as \parindent) use integer arithmetic as TeX internally stores lengths in terms of its sp unit ( 65536 sp = 1 pt). There are, however, some packages that allow you to perform decimal calculations using TeX (see, for example, the calculation topic or the arithmetic topic).

However, first let's look at just integer arithmetic, as that can be performed more efficiently using TeX primitive that using LaTeX packages. TeX count registers are defined using:

\newcountregister cs

This not only allocates a new register, but also assigns a control sequence ⟨register cs⟩ that can be used to reference the register. For example:

\newcount\mycount

allocates a new register that can be referenced using \mycount.

Be careful not to confuse TeX's \newcount with LaTeX's \newcounter command. With the LaTeX version, you provide a label as the argument. Internally, \newcounter uses \newcount to create a register where the control sequence is formed from \c@label⟩ (where ⟨label⟩ is the argument of \newcounter). However, \newcounter performs more than simply assigning a new register. It also provides a command that can be used to format the value of the register (\thelabel⟩), allows the value to be cross-referenced using LaTeX's \label/\ref (along with \refstepcounter), and can also automatically reset the value of the register when another counter is incremented. If I only want a scratch variable to calculate integer values, I'll just define a register using \newcount, as it helps to reduce the clutter of (possibly already complicated code) if I can refer to the register control sequence directly, without the cumbersome use of \value or internal commands. (See, for example, the \julianday register in Example 38.)

A register can be assigned a value using the syntax:

register⟩=⟨value

For example:

\mycount = 25

sets the value of the \mycount register to 25. Note that it's sometimes necessary to use \relax after the assignment to prevent TeX from prematurely expanding the following token. eTeX provides a primitive for evaluating expressions:

\numexprinteger expression

For example:

\mycount=\numexpr(25+5)/3

It's usually a good idea to put \relax after ⟨integer expression⟩ in case it happens to be followed by something that could be interpreted as part of the expression:

\mycount=\numexpr(25+5)/3\relax
-- this assignment is followed by an en-dash.

There is a similar eTeX primitive for evaluating dimension expressions:

\dimexprdimension expression

You can display the value of the register using:

\theregister

For example:

\mycount = 25\relax
\the\mycount

produces:

25

This also works with other types of registers. For example:

\the\textwidth

produces:

349.0pt

There's a similar TeX primitive that works on either a register or a number (either typed explicitly or stored in a macro):

\numbernum

For example:

\mycount = 25
\newcommand{\mynum}{40}%
Register: \number\mycount.
Macro: \number\mynum.
Number: \number46.

Produces:

Register: 25. Macro: 40. Number: 46.

The contents of a register can be incremented using:

\advanceregister⟩ by ⟨value

where ⟨value⟩ may be another register, a macro that expands to a value or a plain number. The by keyword is optional. For example:

\mycount = 12
\advance\mycount by -3
Result: \number\mycount.

produces:

Result: 9.

The contents of a register can be multiplied by a value using:

\multiplyregister⟩ by ⟨value

As with \advance, the keyword by may be omitted. For example:

\mycount = 12
\multiply\mycount by 2
Result: \number\mycount.

produces:

Result: 24.

The contents of a register can be divided by a value using:

\divideregister⟩ by ⟨value

As before the by keyword may be omitted. Remember that this uses integer arithmetic. For example:

\mycount = 25
\divide\mycount by 3
Result: \number\mycount.

produces:

Result: 8.

For decimal arithmetic, there are a number of packages available, such as fp [57] and pgfmath [102]. In addition, the LaTeX3 experimental bundle [50] also provides decimal arithmetic. [LaTeX3 programming] However, it uses LaTeX3 syntax, which is beyond the scope of this book.

The datatool package provides an interface to either fp or pgfmath. The default is to use fp but you can change this using the math=pgfmath package option:

\usepackage[math=pgfmath]{datatool}

The pgfmath package is part of the pgf bundle, so if you intend loading pgf (or tikz) in your document, it's more efficient to use the pgfmath engine with datatool to avoid the overhead of loading an additional package.

The fp and pgfmath packages use very different syntax to perform the same calculations, but datatool provides the same interface commands regardless of the underlying arithmetical package, so you can switch engines without having to change your code, however you may find minor differences in the results, caused by different levels of precision or rounding.

There are two types of arithmetical commands provided by datatool: those that operate on raw plain numbers that use a full stop as the decimal point with no group separator, and those that operate on locale dependent numbers or currency. The first type are prefixed by dtl. For example:

\dtlround{cs}{number}{num digits}

This rounds ⟨number⟩ to ⟨num digits⟩ decimal places and stores the result in the control sequence ⟨cs⟩.

The second type are prefixed by DTL. For example:

\DTLround{cs}{number}{num digits}

which is the locale-dependent alternative to \dtlround.

The plain versions (prefixed with dtl) all perform local assignments. If you need a global assignment you can use \global\let on the result (see §2.1.1 Macro Definitions). For example:

{% local scope
  \dtlround\mynum{14.39999}{2}% perform rounding
  \global\let\mynum\mynum
}
\mynum

The locale versions (prefixed with DTL) come with two alternatives: a local version and a global version. The global versions have the prefix DTLg such as:

\DTLground{cs}{number}{num digits}

which is the global alternative to \DTLround.

For the locale versions, the decimal character defaults to a full stop and the number group separator defaults to a comma, but these can be changed using:

\DTLsetnumberchars{number group char}{decimal char}

where ⟨number group char⟩ is the number group separator and ⟨decimal char⟩ is the decimal character. For example, to switch to commas for the decimal character and a full stop for the number group separator:

\DTLsetnumberchars{.}{,}

Now, any numbers that use this format need to use the control sequences prefixed with DTL instead of dtl:

\DTLsetnumberchars{.}{,}
\DTLround\mynum{1.250,2398}{2}\mynum.

This produces:

1.250

Example (plain numbers):

\dtlround{\mynum}{14.399999999999999}{2}\mynum;
\dtlround{\mynum}{2.5}{2}\mynum.

produces:

14.40; 2.50.

Example (locale numbers):

\DTLround{\mynum}{2,014.399999999999999}{2}\mynum;
\DTLround{\mynum}{1,002.5}{2}\mynum.

produces:

2,014.40; 1,002.5

The locale version \DTLround first converts the formatted number into a plain number, performs the arithmetical operation, and then converts the result back into a formatted number. Therefore, if your numbers are all plain numbers, it's more efficient to use \dtlround instead of \DTLround. Similarly for all the commands described below.

Addition can be performed using:

\dtladd{cs}{number 1}{number 2}

for the plain version, or

\DTLadd{cs}{number 1}{number 2}

for the scoped locale version, or

\DTLgadd{cs}{number 1}{number 2}

for the global locale version. In each case the sum of ⟨number 1⟩ and ⟨number 2⟩ is stored in the control sequence ⟨cs⟩.

Subtraction can be performed using:

\dtlsub{cs}{number 1}{number 2}

for the plain version, or

\DTLsub{cs}{number 1}{number 2}

for the scoped locale version, or

\DTLgsub{cs}{number 1}{number 2}

for the global locale version. In each case ⟨number 1⟩ minus ⟨number 2⟩ is stored in the control sequence ⟨cs⟩.

Multiplication can be performed using:

\dtlmul{cs}{number 1}{number 2}

for the plain version, or

\DTLmul{cs}{number 1}{number 2}

for the scoped locale version, or

\DTLgmul{cs}{number 1}{number 2}

for the global locale version. In each case the product of ⟨number 1⟩ and ⟨number 2⟩ is stored in the control sequence ⟨cs⟩.

Division can be performed using:

\dtldiv{cs}{number 1}{number 2}

for the plain version, or

\DTLdiv{cs}{number 1}{number 2}

for the scoped locale version, or

\DTLgdiv{cs}{number 1}{number 2}

for the global locale version. In each case ⟨number 1⟩ divided by ⟨number 2⟩ is stored in the control sequence ⟨cs⟩.

The absolute value can be obtained using:

\dtlabs{cs}{number}

for the plain version, or

\DTLabs{cs}{number}

for the scoped locale version, or

\DTLgabs{cs}{number}

for the global locale version. In each case the absolute value of ⟨number⟩ is stored in the control sequence ⟨cs⟩.

The negation can be obtained using:

\dtlneg{cs}{number}

for the plain version, or

\DTLneg{cs}{number}

for the scoped locale version, or

\DTLgneg{cs}{number}

for the global locale version. In each case the negative of ⟨number⟩ is stored in the control sequence ⟨cs⟩.

There are also commands available to perform arithmetic operations on a column of data stored in one of datatool's internal database. However, these use the DTL versions and since TeX isn't designed for data management, it's better to perform these calculations in your spreadsheet or when you pull the data from a SQL database.


This book is also available as A4 PDF or 12.8cm x 9.6cm PDF or paperback (ISBN 978-1-909440-07-4).

© 2015 Dickimaw Books. "Dickimaw", "Dickimaw Books" and the Dickimaw parrot logo are trademarks. The Dickimaw parrot was painted by Magdalene Pritchett.

Terms of Use Privacy Policy Cookies Site Map FAQs