Next: Identifiers, Previous: Measurements, Up: GNU troff Reference [Contents][Index]
A numeric expression evaluates to an integer: it can be as simple as a literal ‘0’ or it can be a complex sequence of register and string interpolations interleaved with measurements and operators.
GNU troff
provides a set of mathematical and logical operators
familiar to programmers—as well as some unusual ones—but supports
only integer arithmetic.^{35} The internal data type
used for computing results is usually a 32bit signed integer, which
suffices to represent magnitudes within a range of ±2
billion.^{36}
Arithmetic infix operators perform a function on the numeric expressions
to their left and right; they are +
(addition), 
(subtraction), *
(multiplication), /
(truncating
division), and %
(modulus). Truncating division rounds to
the integer nearer to zero, no matter how large the fractional portion.
Overflow and division (or modulus) by zero are errors and abort
evaluation of a numeric expression.
Arithmetic unary operators operate on the numeric expression to their
right; they are 
(negation) and +
(assertion—for
completeness; it does nothing). The unary minus must often be used
with parentheses to avoid confusion with the decrementation operator,
discussed below.
Observe the rounding behavior and effect of negative operands on the modulus and truncating division operators.
.nr T 199/100 .nr U 5/2 .nr V (5)/2 .nr W 5/2 .nr X 5%2 .nr Y (5)%2 .nr Z 5%2 T=\n[T] U=\n[U] V=\n[V] W=\n[W] X=\n[X] Y=\n[Y] Z=\n[Z] ⇒ T=1 U=2 V=2 W=2 X=1 Y=1 Z=1
The sign of the modulus of operands of mixed signs is determined by the sign of the first. Division and modulus operators satisfy the following property: given a dividend a and a divisor b, a quotient q formed by ‘(a / b)’ and a remainder r by ‘(a % b)’, then qb + r = a.
GNU troff
’s scaling operator, used with parentheses as
(c;e)
, evaluates a numeric expression e
using c as the default scaling unit. If c is omitted,
scaling units are ignored in the evaluation of e. This
operator can save typing by avoiding the attachment of scaling units to
every operand out of caution. Your macros can select a sensible default
unit in case the user neglects to supply one.
.\" Indent by amount given in first argument; assume ens. .de Indent . in (n;\\$1) ..
Without the scaling operator, the foregoing macro would, if called with
a unitless argument, cause indentation by the in
request’s
default scaling unit (ems). The result would be twice as much
indentation as expected.
GNU troff
also provides a pair of operators to compute the
extrema of two operands: >?
(maximum) and <?
(minimum).
.nr slots 5 .nr candidates 3 .nr salaries (\n[slots] <? \n[candidates]) Looks like we'll end up paying \n[salaries] salaries. ⇒ Looks like we'll end up paying 3 salaries.
Comparison operators comprise <
(less than), >
(greater
than), <=
(less than or equal), >=
(greater than or
equal), and =
(equal). ==
is a synonym for =
.
When evaluated, a comparison is replaced with ‘0’ if it is false
and ‘1’ if true. In the roff
language, positive values are
true, others false.
We can operate on truth values with the logical operators &
(logical conjunction or “and”) and :
(logical disjunction or
“or”). They evaluate as comparison operators do.
A logical complementation (“not”) operator, !
, works only
within if
, ie
, and while
requests.
Furthermore, !
is recognized only at the beginning of a numeric
expression not contained by another numeric expression. In other words,
it must be the “outermost” operator. Including it elsewhere in the
expression produces a warning in the ‘number’ category
(see Warnings), and its expression evaluates false. This
unfortunate limitation maintains compatibility with AT&T
troff
. Test a numeric expression for falsity by
comparing it to a false value.^{37}
.nr X 1 .nr Y 0 .\" This does not work as expected. .if (\n[X])&(!\n[Y]) .nop A: X is true, Y is false . .\" Use this construct instead. .if (\n[X])&(\n[Y]<=0) .nop B: X is true, Y is false error→ warning: expected numeric expression, got '!' ⇒ B: X is true, Y is false
The roff
language has no operator precedence: expressions are
evaluated strictly from left to right, in contrast to schoolhouse
arithmetic. Use parentheses (
)
to impose a desired
precedence upon subexpressions.
.nr X 3+5*4 .nr Y (3+5)*4 .nr Z 3+(5*4) X=\n[X] Y=\n[Y] Z=\n[Z] ⇒ X=32 Y=32 Z=23
For many requests and escape sequences that cause motion on the page,
the unary operators +
and 
work differently when leading
a numeric expression. They then indicate a motion relative to the
drawing position: positive is down in vertical contexts, right in
horizontal ones.
+
and 
are also treated differently by the following
requests and escape sequences: bp
, in
, ll
,
lt
, nm
, nr
, pl
, pn
, po
,
ps
, pvs
, rt
, ti
, \H
, \R
, and
\s
. Here, leading plus and minus signs serve as incrementation
and decrementation operators, respectively. To negate an expression,
subtract it from zero or include the unary minus in parentheses with its
argument. See Setting Registers, for examples.
A leading 
operator indicates a motion relative not to the
drawing position but to a boundary. For horizontal motions, the
measurement specifies a distance relative to a drawing position
corresponding to the beginning of the input line. By default,
tab stops reckon movements in this way. Most escape sequences do not;

tells them to do so.
Mind the \h'1.2i'gap. .br Mind the \h'1.2i'gap. .br Mind the \h'1.2i'gap. ⇒ Mind the gap. ⇒ Mind the gap. ⇒ Mind the gap.
One use of this feature is to define macros whose scope is limited to the output they format.
.\" underline word $1 with trailing punctuation $2 .de Underline . nop \\$1\l'0\[ul]'\\$2 .. Typographical emphasis is best used .Underline sparingly .
In the above example, ‘0’ specifies a negative motion from the
current position (at the end of the argument just emitted, \$1
)
to the beginning of the input line. Thus, the \l
escape sequence
in this case draws a line from right to left. A macro call occurs at
the beginning of an input line;^{38} if the 
operator were omitted, then the underline would be drawn at zero
distance from the current position, producing devicedependent, and
likely undesirable, results. On the ‘ps’ output device, it
underlines the period.
For vertical motions, the 
operator specifies a distance from
the first text baseline on the page or in the current
diversion,^{39} using the current vertical
spacing.
A .br B \Z'C'\v'0'D ⇒ A D ⇒ B C
In the foregoing example, we’ve used the \Z
escape sequence
(see Page Motions) to restore the drawing position after formatting
‘C’, then moved vertically to the first text baseline on the page.
'
anything'
Interpolate 1 if anything is a valid numeric expression, and 0 otherwise. The delimiter need not be a neutral apostrophe; see Delimiters.
You might use \B
along with the if
request to filter out
invalid macro or string arguments. See Conditionals and Loops.
.\" Indent by amount given in first argument; assume ens. .de Indent . if \B'\\$1' .in (n;\\$1) ..
A register interpolated as an operand in a numeric expression must have an Arabic format; luckily, this is the default. See Assigning Register Formats.
Because spaces separate arguments to requests, spaces are not allowed in numeric expressions unless the (sub)expression containing them is surrounded by parentheses. See Invoking Requests, and Conditionals and Loops.
.nf .nr a 1+2 + 2+1 \na error→ expected numeric expression, got a space ⇒ 3 .nr a 1+(2 + 2)+1 \na ⇒ 6
The nr
request (see Setting Registers) expects its second and
optional third arguments to be numeric expressions; a bare +
does
not qualify, so our first attempt got a warning.
Next: Identifiers, Previous: Measurements, Up: GNU troff Reference [Contents][Index]