Hi Francesco,

At 2025-02-21T16:19:25+0100, Francesco Ariis wrote:
>     can I format/scale numbers when interpolating them?

Not without arithmetic, as far as I know.

> Long explanation follows.
> 
> While writing a minimal reproducible example for this list,
> I found myself typing:
> 
>     Line length is set to:
>     .nr calc \n[.l]/1c
>     \n[calc]
> 
> Notice how, to interpolate line length in centimetres: I picked
> an auxiliary register, scaled the number to centimetres, and then
> displayed it.

Right.  I think this is the most straightforward approach that exists;
arbitrary numeric expressions cannot be directly interpolated--there's
no escape sequence for that.  (If we wanted one, I notice that `\=` is
available.)  So what one does instead is assign the numeric expression
of interest to a register and then interpolate that.

> I am sure I am not the first one wanting to format number output.
> Is there a way to — say — \n[my-id]c to have a register interpolated
> in a specific scaling unit?

No.  GNU troff has as an extension a scaling operator `;`, but it's used
for the opposite purpose: application of scaling units to quantities on
their way to register values, which are always in basic units,
subdivided ("scaled") points, or dimensionless.

What one might call an "outbound" scaling operator does not exist in the
language.

I further observe that a loss of precision threatens.

$ cat EXPERIMENTS/unit-conversion.groff
.nf
.nr basic-units-per-cm 1c
There are \n[basic-units-per-cm] basic units per centimeter.
The line length is \n[.l] basic units.
.nr line-length-in-cm \n[.l]/1c
The line length is \n[line-length-in-cm]\~cm.
$ groff -a EXPERIMENTS/unit-conversion.groff
<beginning of page>
There are 28346 basic units per centimeter.
The line length is 468000 basic units.
The line length is 16 cm.

That's pretty coarse.  The default line length on the PostScript device
is 6.5 inches (468000u), and at 2.54cm per inch, the true line length is
closer to 16.51cm.

The usual remedy in this situations is to use scaled integer arithmetic,
multipling all quantities of interest by a factor (often a power of ten)
sufficient to preserve the desired precision through division
operations.

Here's a crude example.

$ cat EXPERIMENTS/unit-conversion2.groff
.nf
.nr basic-units-per-cm 1c
.nr scale-factor 1000u \" 10, 100, or 1000; 10000 overflows
We're subdividing the centimeter by \n[scale-factor] for arithmetic.
.nr basic-units-per-subcm 1c*\n[scale-factor]
There are \n[basic-units-per-subcm] basic units per subdivided centimeter.
The line length is \n[.l] basic units.
.nr line-length-in-subcm \n[.l]*\n[scale-factor]/\n[basic-units-per-cm]
The line length is \n[line-length-in-subcm] in subdivided centimeters.
.nr line-length-in-cm \n[line-length-in-subcm]/\n[scale-factor]u
The line length is \n[line-length-in-cm]\~cm.
$ groff -a EXPERIMENTS/unit-conversion2.groff
<beginning of page>
We're subdividing the centimeter by 1000 for arithmetic.
There are 28346000 basic units per subdivided centimeter.
The line length is 468000 basic units.
The line length is 16510 in subdivided centimeters.
The line length is 16 cm.

As noted in the comment, scaled integer arithmetic can pinch on systems
with 32-bit `int` type in C/C++, like amd64/x86-64.

The "Numeric expressions" section of the groff(7) man page is worth
review when considering the possibilities and limitations of arithmetic
in the groff language.  (Our Texinfo manual covers the same material.)
Among other things, it notes that division truncates rather than
rounding.

https://man7.org/linux/man-pages/man7/groff.7.html#Numeric_expressions

Regards,
Branden

Attachment: signature.asc
Description: PGP signature

Reply via email to