## digitalmars.D - modulus and array.length

- David Osborne (52/52) Nov 16 2010 Hi,
- Steven Schveighoffer (9/61) Nov 16 2010 Simple, array.length is an unsigned value, so the signed operands are
- =?UTF-8?B?IkrDqXLDtG1lIE0uIEJlcmdlciI=?= (17/28) Nov 16 2010 Like others have said, this is due to the fact that when one
- Kagamin (2/9) Nov 16 2010 It's rather (x/n)+(x%n)==x
- =?UTF-8?B?IkrDqXLDtG1lIE0uIEJlcmdlciI=?= (8/18) Nov 16 2010 That is (part of) the definition of the *remainder* operation. The
- bearophile (4/5) Nov 16 2010 Yup, bug 3843.
- David Osborne (3/3) Nov 16 2010 Thanks for the info, everyone. I guess I'll just have to be more carefu...

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

Nov 16 2010

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

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 0Like 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 =20This is consistent with the C behaviour. Note that according to the 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

Jérôme M. Berger Wrote:It's rather (x/n)+(x%n)==x-3 mod 3 = 0 -2 mod 3 = -2 -1 mod 3 = -1 0 mod 3 = 0Note 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.

Nov 16 2010

Kagamin wrote:J=C3=A9r=C3=B4me M. Berger Wrote: =20That 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=20 It's rather (x/n)+(x%n)=3D=3Dx-3 mod 3 =3D 0 -2 mod 3 =3D -2 -1 mod 3 =3D -1 0 mod 3 =3D 0Note 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.

Nov 16 2010

J. M. Berger:(bearophile probably has a bug report for it ;) )Yup, bug 3843. Bye, bearophile

Nov 16 2010

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

Nov 16 2010