guile-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Commentary: R6RS div0-and-mod0 vs Taylor's `round/'


From: Mark H Weaver
Subject: Commentary: R6RS div0-and-mod0 vs Taylor's `round/'
Date: Sun, 30 Jan 2011 01:02:44 -0500
User-agent: Gnus/5.13 (Gnus v5.13) Emacs/23.1 (gnu/linux)

Hello all,

I decided to search for the rationale for the R6RS `div0-and-mod0' set
of operators.  Here's what I found from Will Clinger:

  http://srfi.schemers.org/srfi-77/mail-archive/msg00505.html

What I take from this is that the designers of the R6RS division
operators placed emphasis on the range of the remainder, to make it as
compact and predictable as possible.  The rounding policy of the
quotient is considered unimportant; it must be whatever makes the
remainder fit in the specified range.  In the case of integer inputs
with divisor D, both `mod' and `mod0' produce exactly D possible values,
and that set of values depends only on the magnitude of D, not on the
sign of N or D.

In contrast, Taylor Campbell's proposal puts all emphasis on the
rounding policy of his quotient operators, with the range of remainders
considered secondary.

  http://trac.sacrideo.us/wg/wiki/DivisionRiastradh

A case in point is Taylor's `round/' operator, which is _almost_
identical to the R6RS `div0-and-mod0'.  They only time they produce
different results is when the quotient is exactly half-way between two
integers, and for integer arguments this can happen only when D is even.
In this case, Taylor chooses to round to the even integer, and this
implies that the set of possible remainders is not D but rather D+1.

Another way to look at it is as follows: if you set D to some fixed
integer and look at the output of (mod N D) as N loops over all the
integers, then both R6RS `mod' and `mod0' will simply cycle through
exactly D possible outputs.  However, `round-remainder' does not quite
do this when D is even.  It will mostly cycle through its outputs,
except for the two most extreme values, which are hit only half as often
as all the others.  Each time around the cycle, it will alternate which
one it hits.  Basically, the minimum value of `mod0' has been split into
two different values in `round-remainder', increasing the total number
of possible values from D to D+1.  Personally, I think this is a poorly
designed set of division operators.

For those who are curious, given the contraints on `mod0's output range,
`div0's rounding policy turns out to be as follows: half-integer
quotients are rounded toward +inf when the divisor D is positive, and
toward -inf when D is negative.

Personally, I think that `div0-and-mod0' is far superior to `round/',
because I think the range of remainders is much more important than how
one rounds the half-integer quotients.

As for the difference between R6RS `div-and-mod' (Taylor's `euclidean/')
and `floor/', I don't think it matters much.  In the cases I know of
where the set of remainder values is important, D is generally positive,
in which case `floor/' and `euclidean/' are the same.

Taylor's `truncate/' (the same as R5RS quotient and remainder, as well
as the C operators `/' and `%') have a different problem.  If you use
the outputs of % to index into a table, typically the divisor D is fixed
but the dividend N may be less predictable.  In this case you must be
careful that the dividend N does not change sign.  If it does, the
remainder will change sign.  This is a possible source of bugs.

In some rare cases `truncate/' may truly be what you want, but in my
experience, `euclidean/' is the most generally useful, and `floor/' is
almost as good.  The primary advantage to `truncate/' is that it is what
most processors (and thus C) supports directly, and thus it can be
implemented much more efficiently than the other division operators.

      Mark



reply via email to

[Prev in Thread] Current Thread [Next in Thread]