groff
[Top][All Lists]

## Re: [Groff] Mission statement

 From: Ted Harding Subject: Re: [Groff] Mission statement Date: Sun, 16 Mar 2014 16:49:55 -0000 (GMT)

```On 15-Mar-2014 09:52:59 Ralph Corderoy wrote:
> Hi Ingo,
>
>> > - real number arithmetic to replace current integer arithmetic
>>
>> Do you really mean "replace", or rather something like "complement"
>> or "provide in addition to"?  If you do mean "replace", i fear
>> compatibility issues.  Besides, isn't integer arithmetics better
>> suited to some tasks than real number arithmetic?
>
> I wouldn't have thought it could replace.  I think Ted has uses for it,
> IIRC.  As Werner says, Decimal might be a better bet than floating-point.
> Or would fixed-point be good enough, like dc(1) provides?  Ted?

Werner's suggestion was to use decimal arithmetic (i.e. working in
base 10) rather than binary (working in base 2). There are indeed
rounding issues when working in binary but needing the results in
decimal! There may well be an argument for this.

In this reply, I would like to comment on my principal need for
replacing integer arithmetic. There are indeed many contexts in
which troff accepts decimal fractions -- for example, one can
write "\h'0.33m'", ".sp 0.25v", and the like, where the fractional
quantity is entered explicitly. One can even set a fractional point
size explicitly (once one has got one's head around "scaled points").

The problems arise when one wants to compute a number with a
fractional part by entering an arithmetical expression for it.
Since groff uses integer arithmetic, any fractional part in the
resuit (or in any intermediate result arising during evaluation)
will be dropped. Thus, for instance,

.nr temp 2/3  -->  \n[temp]=0
.nr temp 7/3  -->  \n[temp]=2

My most frequent need for fractional arithmetic is in computing
fractional point sizes. I do a lot of mathematics, sometimes with
uper/subscripts going to the 3rd or even 4th order, e.g.

\$X sup V sup 2\$
or
\$X sup V sup 2 sup z\$

What eqn does when reducing point sizes for these is, at each stage,
issue a troff request

.ps (u;\\n[.ps]*7+5/10>?5)

whose effect is that provided the result exceeds 5 [points] use
this as the point-size; otherwise use 5 points.

So, for instance, if initially in 10-point this sets the point-size to
10*7[=70]+5[=75]/10 = 7, for a 1st-order superscript. For the 2nd-order
this then becomes 7*7[=49]+5[=54]/10 = 5. (Note the use of left->right
precedence in the evaluations; and the dropping of fractional parts).

Therefore for a range of initial point-sizes we have, at succesive
superscript levels (up to 4th-order),

10 ->  7 -> 5 -> 5 -> 5
11 ->  8 -> 6 -> 5 -> 5
12 ->  8 -> 6 -> 5 -> 5
13 ->  9 -> 6 -> 5 -> 5
14 -> 10 -> 7 -> 5 -> 5
15 -> 11 -> 8 -> 6 -> 5

Note especially the "12" one, which evaluates as 12*7[=84]+5[=89]/10 = 8
(which, in fractional arithmetic, would be 89/10 = 8.9, so the result
is almost 1 point smaller than one would proportionally wish).

I have (partially) worked round this where eqn is concerned by defining

.\" Macro to modify superscript reduction factor in 'eqn'
.nr PSeqnnum 11
.nr PSeqnden 14
.nr PSeqnrnd 7
.nr PSeqnmin 5
.de PSeqn
.\".\".ps (u;\\n[.ps]*7+5/10>?5)
.ps (u;\\n[.ps]*\\n[PSeqnnum]+\\n[PSeqnrnd]/\\n[PSeqnden]>?\\n[PSeqnmin])
..

so that (with the above "default" settings) the expression is now:

.ps (u;\\n[.ps]*11+7/14>?5)

The difference this makes to the results is (above table at the left):

10 ->  7 -> 5 -> 5 -> 5 || 10 ->  8 -> 6 -> 5 -> 5
11 ->  8 -> 6 -> 5 -> 5 || 11 ->  9 -> 7 -> 5 -> 5
12 ->  8 -> 6 -> 5 -> 5 || 12 ->  9 -> 7 -> 5 -> 5
13 ->  9 -> 6 -> 5 -> 5 || 13 -> 10 -> 8 -> 6 -> 5
14 -> 10 -> 7 -> 5 -> 5 || 14 -> 11 -> 8 -> 6 -> 5
15 -> 11 -> 8 -> 6 -> 5 || 15 -> 12 -> 8 -> 6 -> 5

which is clearly somewhat (though not hugely) better -- the result
will still always be an integer-point size! The values I chose for
the constants in the expression were motivated by aiming for a
reduction by 1/cuberoot(2) as one moves up one level of superscript,
so that the point size of "z" in "\$X sup V sup 2 sup z\$" would be
about half that of X: cuberoot(2) = 1.26, 14/11 = 1.27 -- but only
using small multipliers (since ".ps (u;\\n[.ps]*11+7/14>?5)" is
set to work in "u", which for PS is points*1000, so 11-point is
11000u; and you could easily provoke overflow).

It would be much nicer if one could use "".ps (u;\\n[.ps]/1.26>?5)"!

The implementation of the above in the bash script under which I run
groff (which also implements a "delayed WYSIWYG") involves piping the
eqn output through a 'sed' modification:

... | eqn -Tps | /usr/local/bin/ge.sedit \ ...

where the "ge.sedit" script is:

#! /bin/bash
sed '/\.ps (u;\\n\[\.ps\]\*7+5\/10>?5)/s/ps/PSeqn/'

which locates the string "\.ps (u;\\n\[\.ps\]\*7+5\/10>?5)" as output
by eqn, and replaces the first occurrence of "ps" in it by my modified
version "ps (u;\\n[.ps]*11+7/14>?5)" (defined as "PSeqn as above), so
what gets fed to troff is the line

.PSeqn (u;\\n\[\.ps\]\*7+5\/10>?5)

But, since my macro ".PSeqn" does not look for external arguments,
the "(u;\\n\[\.ps\]\*7+5\/10>?5)" is ignored.

Now, all that is quite a convoluted caper! Much easier if groff was
not limited to integers arithmetic and allowed fractions in the results!

That's it on this point! I may comment on the syntax for arithmetic
expressions later; briefly, though, I'm not too fussy about the current
"left->right evaluation" method. It's awkward, but it can be made to
work -- and working is what matters!

On a closely related issue: I quite regularly need to compute, within
a groff run, a numerical value which has a fractional part for insertion
in the text, or for computing fractional spacings, motions, etc. This
can be done using 'pic', which has good computational capabilities
-- though again a bit of "work-around" is involved, since one must arrange
that the call to 'pic' using ".PS/.../.PE" produces no visible effect
at the text position where it occurrs. This I have done by incorporating
an additional argument to the ".PS" macro in the "ms" macro set, so that
it causes no line breaks and inserts no vertical space. This is "T", so
the call is ".PST"/<computation>/.PE"; and "T" stands for "Tacit" (i.e.
get on with the task and don't let me hear a sound from you while you're
doing it)!

Best wishes to all,
Ted.

-------------------------------------------------