|
|
Bugzilla Link |
1042 |
Created on |
Jan 09, 2013 15:16 |
Version |
svn |
OS |
Linux |
Architecture |
PC |
Extended Description
I have been looking at the SAC stdlib rotate (and shift)
functions, as they relate to AWLF, and this led me to
look at the definition of the _mod_()
primitive in SAC. I find it wanting, for several reasons.
The underlying challenge is to make AWLF/WLF operate
with rotate as a producer WL and as a consumer WL.
The existing stdlib code uses mod() and a conditional
to normalize the rotate count. I.e., map it
into a non-negative integer
in the range 0...(N-1), where N is the length of
the rotation axis. In the common cases
where the rotate count is a constant, this is not
a problem. However, in APL code, we often see
expressions such as this one, to drop the leading
blanks from a text vector:
((vec≠' ')⍳1) ↓ vec
or
((vec≠' ')⍳1) ⌽ vec
I do not know what the design rationale was for the mod()
primitive, but suspect it was intended to mimic the
behavior of the (equally ill-defined) a%b (remainder)
operation in C.
1. According to the C99 standard*, the result is defined only
if "...the quotient a/b is representable". E.g.,
0%0 is undefined.
For rotate() arguments where the rotate count ends up being
zero, this can cause the normalization of the rotate count
to signal an error.
In APL, where considerable thought was
given to the definition of residue (aka remainder) on
all integers, floats, and complex numbers,
0 | 0 ( 0%0 in C) is defined to produce 0.
2. In K&R (2nd Edition), "the sign of the result for
% {is} machine-dependent for negative operands."
By constrast, in APL, the definition is clearly specified for
all integer (and, in fact, all numeric) arguments. NB.
argument order is reversed in SAC from that of APL:
¯5 ¯4 ¯3 ¯2 ¯1 0 1 2 3 4 NB. A
0 1 2 3 4 0 1 2 3 4 NB. 5|A (AKA A%5)
This is not the same as the current behavior of the SAC
mod() primitive on negative A:
-5 -4 -3 -2 -1 0 1 2 3 4 NB. A
-5 -4 -3 -2 -1 0 1 2 3 4 NB. A%5
Note that the APL definition maps a negative
rotate count into the correct non-negative count.
The SAC behavior requires checking for a negative
count and then adding b to the count for negatives.
This often inhibits the ability to perform AWLF on
rotated arguments/results, because of problems
around partition/index vector intersect calculation.
Furthermore, it may be that the SAC definition is
"implementation-dependent", in which case we are
left in a position of not being able even to specify the
behavior of the stdlib rotate() function. It could screw
anyone running on an implementation (e.g., Windows?) that produces
different results.
If we are going to define stdlib functions on SAC primitives,
then we need to define the precise semantics of those
primitives, and eschew "implementation-dependent"
behavior.
So, a few questions,and a few proposals for redefinition:
Q1: Does anybody depend on the result of SAC
mod() on negative or zero arguments?
Q2: Are there concrete objections to extending the definition
of SAC mod() to handle zeros and negative arguments
in the same way that APL does, thereby avoiding
any arguments about "implementation-defined"
behavior there and in the stdlib?
P0: If the answers to Q1 and Q2 are No, I propose to
change sac2c mod() to operate as APL does, and
to change the stdlib rotate() functions to rely on
that definition.
2013-01-09: I have not heard any response from sacdev or others
on this topic. Silence is consent, in my book, so I am going
to proceed with the above implementation, as proposed.
* This is a draft of same:
http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf