## digitalmars.D - modulus and array.length

David Osborne <krendilboove gmail.com> writes:
```--0016364994b7ad451204952d95c5
Content-Type: text/plain; charset=ISO-8859-1

Hi,

I've noticed that the modulus operator acts differently when the divisor is
the length of an array and the dividend is negative.
For instance, this code:

import std.stdio;
const int x = 4;
void main(){
int[x] arr = [0, 1, 2, 3];

writeln("Using arr.length");
for(int i = -3; i <= 0; i++){
writefln("%d mod %d = %d", i, arr.length, i % arr.length);
}
writeln("Using x");
for(int i = -3; i <= 0; i++){
writefln("%d mod %d = %d", i, x, i % x);
}
}

Produces this output:

Using arr.length
-3 mod 4 = 1
-2 mod 4 = 2
-1 mod 4 = 3
0 mod 4 = 0
Using x
-3 mod 4 = -3
-2 mod 4 = -2
-1 mod 4 = -1
0 mod 4 = 0

Which is a useful (but undocumented?) feature that lets you loop through
arrays backwards.
However, when the length of the array is odd...
const int x = 3;
...
int[x] arr = [0, 1, 2];
It looks like this:

Using arr.length
-3 mod 3 = 1  <-- this should be 0
-2 mod 3 = 2  <-- this should be 1
-1 mod 3 = 0  <-- this should be 2
0 mod 3 = 0
Using x
-3 mod 3 = 0
-2 mod 3 = -2
-1 mod 3 = -1
0 mod 3 = 0

Does anyone know of a reason for this? It doesn't seem like a bug, but I
don't know why it would do something like that.

Upon further investigation, I found that when arr.length is even, i acts
like (x*(abs(i)/x + 1) + i) , and when arr.length is odd, i acts like
(x*(abs(i)/x - 1) + i)

(I'm using dmd 2.049 on linux)

~Dave

Content-Type: text/html; charset=ISO-8859-1
Content-Transfer-Encoding: quoted-printable

Hi,<br><br>I&#39;ve noticed that the modulus operator acts differently when=
the divisor is the length of an array and the dividend is negative.<br>For=
instance, this code:<br style=3D"margin: 0pt 0pt 0pt 0.8ex; border-left: 1=
px solid rgb(204, 204, 204); padding-left: 1ex;" class=3D"gmail_quote">

<br><div style=3D"margin-left: 40px;">import std.stdio;<br>const int x =3D =
4;<br>void main(){<br>=A0=A0=A0 int[x] arr =3D [0, 1, 2, 3];<br>=A0=A0=A0 <=
br>=A0=A0=A0 writeln(&quot;Using arr.length&quot;);<br>=A0=A0=A0 for(int i =
=3D -3; i &lt;=3D 0; i++){<br>

=A0=A0=A0 =A0=A0=A0 writefln(&quot;%d mod %d =3D %d&quot;, i, arr.length, i=
% arr.length);<br>=A0=A0=A0 }<br>=A0=A0=A0 writeln(&quot;Using x&quot;);<b=
r>=A0=A0=A0 for(int i =3D -3; i &lt;=3D 0; i++){<br>=A0=A0=A0 =A0=A0=A0 wri=
tefln(&quot;%d mod %d =3D %d&quot;, i, x, i % x);<br>

=A0=A0=A0 }<br>}<br></div><br>Produces this output:<br><br><div style=3D"ma=
rgin-left: 40px;">Using arr.length<br>-3 mod 4 =3D 1<br>-2 mod 4 =3D 2<br>-=
1 mod 4 =3D 3<br>0 mod 4 =3D 0<br>Using x<br>-3 mod 4 =3D -3<br>-2 mod 4 =
=3D -2<br>-1 mod 4 =3D -1<br>

0 mod 4 =3D 0<br><br></div>=A0Which is a useful (but undocumented?) feature=
that lets you loop through arrays backwards.<br>However, when the length o=
f the array is odd...<br><div style=3D"margin-left: 40px;">const int x =3D =
3;<br>

...<br>int[x] arr =3D [0, 1, 2];<br></div>It looks like this:<br><br><div s=
tyle=3D"margin-left: 40px;">Using arr.length<br>-3 mod 3 =3D 1=A0 &lt;-- th=
is should be 0<br>-2 mod 3 =3D 2=A0 &lt;-- this should be 1<br>-1 mod 3 =3D=
0=A0 &lt;-- this should be 2<br>
0 mod 3 =3D 0<br>Using x<br>-3 mod 3 =3D 0<br>
-2 mod 3 =3D -2<br>-1 mod 3 =3D -1<br>0 mod 3 =3D 0<br><br></div>Does anyon=
e know of a reason for this? It doesn&#39;t seem like a bug, but I don&#39;=
t know why it would do something like that.<br><br>Upon further investigati=
on, I found that when arr.length is even, i acts like (x*(abs(i)/x + 1) + i=
) , and when arr.length is odd, i acts like (x*(abs(i)/x - 1) + i) <br>

<br>(I&#39;m using dmd 2.049 on linux)<br><br><br>~Dave<br><div style=3D"ma=
rgin-left: 40px;"><br></div>

```
Nov 16 2010
"Steven Schveighoffer" <schveiguy yahoo.com> writes:
```On Tue, 16 Nov 2010 10:55:24 -0500, David Osborne <krendilboove gmail.com>
wrote:

Hi,

I've noticed that the modulus operator acts differently when the divisor
is
the length of an array and the dividend is negative.
For instance, this code:

import std.stdio;
const int x = 4;
void main(){
int[x] arr = [0, 1, 2, 3];

writeln("Using arr.length");
for(int i = -3; i <= 0; i++){
writefln("%d mod %d = %d", i, arr.length, i % arr.length);
}
writeln("Using x");
for(int i = -3; i <= 0; i++){
writefln("%d mod %d = %d", i, x, i % x);
}
}

Produces this output:

Using arr.length
-3 mod 4 = 1
-2 mod 4 = 2
-1 mod 4 = 3
0 mod 4 = 0
Using x
-3 mod 4 = -3
-2 mod 4 = -2
-1 mod 4 = -1
0 mod 4 = 0

Which is a useful (but undocumented?) feature that lets you loop through
arrays backwards.
However, when the length of the array is odd...
const int x = 3;
...
int[x] arr = [0, 1, 2];
It looks like this:

Using arr.length
-3 mod 3 = 1  <-- this should be 0
-2 mod 3 = 2  <-- this should be 1
-1 mod 3 = 0  <-- this should be 2
0 mod 3 = 0
Using x
-3 mod 3 = 0
-2 mod 3 = -2
-1 mod 3 = -1
0 mod 3 = 0

Does anyone know of a reason for this? It doesn't seem like a bug, but I
don't know why it would do something like that.

Upon further investigation, I found that when arr.length is even, i acts
like (x*(abs(i)/x + 1) + i) , and when arr.length is odd, i acts like
(x*(abs(i)/x - 1) + i)

(I'm using dmd 2.049 on linux)

Simple, array.length is an unsigned value, so the signed operands are
promoted to unsigned through normal integer promotion:

cast(uint)-3 -> 4_294_967_293u
4_294_967_293u % 3u -> 1

I don't think this "undocumented" feature is valid.  In fact, it may not
be valid for evens as well that aren't powers of 2.

-Steve
```
Nov 16 2010
=?UTF-8?B?IkrDqXLDtG1lIE0uIEJlcmdlciI=?= <jeberger free.fr> writes:
```Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: quoted-printable

David Osborne wrote:
Using arr.length
-3 mod 3 =3D 1  <-- this should be 0
-2 mod 3 =3D 2  <-- this should be 1
-1 mod 3 =3D 0  <-- this should be 2
0 mod 3 =3D 0

Like others have said, this is due to the fact that when one
operand is unsigned (here the length), then all operands get casted
to unsigned before the operation. Several people have asked that
array length be changed to a signed value because of that
(bearophile probably has a bug report for it ;) )

Using x
-3 mod 3 =3D 0
-2 mod 3 =3D -2
-1 mod 3 =3D -1
0 mod 3 =3D 0
=20

C standard, the result of the modulus operation with negative
arguments is undefined. I don't remember if Walter has specified the
expected behaviour for D or if he left it undefined...

Note that from a strictly mathematical point of view, this result
is valid: for all x and all n, x-(x%n) is a multiple of n.

Jerome
--=20
mailto:jeberger free.fr
http://jeberger.free.fr
Jabber: jeberger jabber.fr
```
Nov 16 2010
Kagamin <spam here.lot> writes:
```Jérôme M. Berger Wrote:

-3 mod 3 = 0
-2 mod 3 = -2
-1 mod 3 = -1
0 mod 3 = 0

Note that from a strictly mathematical point of view, this result
is valid: for all x and all n, x-(x%n) is a multiple of n.

It's rather (x/n)+(x%n)==x
```
Nov 16 2010
=?UTF-8?B?IkrDqXLDtG1lIE0uIEJlcmdlciI=?= <jeberger free.fr> writes:
```Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: quoted-printable

Kagamin wrote:
J=C3=A9r=C3=B4me M. Berger Wrote:
=20
-3 mod 3 =3D 0
-2 mod 3 =3D -2
-1 mod 3 =3D -1
0 mod 3 =3D 0

is valid: for all x and all n, x-(x%n) is a multiple of n.

It's rather (x/n)+(x%n)=3D=3Dx

That is (part of) the definition of the *remainder* operation. The
definition of *modulus* is looser.

Jerome
--=20
mailto:jeberger free.fr
http://jeberger.free.fr
Jabber: jeberger jabber.fr
```
Nov 16 2010
bearophile <bearophileHUGS lycos.com> writes:
```J. M. Berger:

(bearophile probably has a bug report for it ;) )

Yup, bug 3843.

Bye,
bearophile
```
Nov 16 2010
David Osborne <krendilboove gmail.com> writes:
```--0016e64967c82764a3049534aa58
Content-Type: text/plain; charset=ISO-8859-1

Thanks for the info, everyone.  I guess I'll just have to be more careful
what I use modulus with :)

~Dave

--0016e64967c82764a3049534aa58
Content-Type: text/html; charset=ISO-8859-1
Content-Transfer-Encoding: quoted-printable

<br>Thanks for the info, everyone.=A0 I guess I&#39;ll just have to be more=
careful what I use modulus with :)<br><br>~Dave<br>

--0016e64967c82764a3049534aa58--
```
Nov 16 2010