Strange behavior of modulo in array index

  • Thread starter Thread starter Guest
  • Start date Start date
G

Guest

I have a loop which iterates over an array in a particular order:

for (j = 0; j < 16; j++) T[(4 - j) % 4] = ...;

The loop proceeds normally for j = 0 through j = 4, but gives an
IndexOutOfRangeException at j = 5. Playing with the watch window seems to
indicate that the modulo is being completely ignored:

j = 0x5 (int)
T[(4 - j) % 4] = error: index '4-j%4' out of bound for pointer/array 'T'
(4 - j) % 4 = 0xffffffff (int)
4 - j = 0xffffffff (int)
0xffffffff % 4 = 0x3 (long)

I'm stumped. Any ideas?
 
Hi Ben,

-1 % 4 = -1 that is the correct result (0*4 - 1).
Unless T is collection that you have written by yourself and it supposrts
negative indices or dictionalry any other .NET collection or array will
throw that exception
 
Ben Blank said:
I have a loop which iterates over an array in a particular order:

for (j = 0; j < 16; j++) T[(4 - j) % 4] = ...;

The loop proceeds normally for j = 0 through j = 4, but gives an
IndexOutOfRangeException at j = 5. Playing with the watch window seems to
indicate that the modulo is being completely ignored:

j = 0x5 (int)
T[(4 - j) % 4] = error: index '4-j%4' out of bound for pointer/array 'T'
(4 - j) % 4 = 0xffffffff (int)
4 - j = 0xffffffff (int)
0xffffffff % 4 = 0x3 (long)

I'm stumped. Any ideas?

It's not being ignored at all. The range for x % y is (-y, y) (note
exclusivity of bounds).

Note that it's the remainder operator, not the modulo operator, which
is why there's the difference. (There's no modulo operator.)
 
Stoitcho Goutsev (100) said:
-1 % 4 = -1 that is the correct result (0*4 - 1).

Odd. I was under the impression that modulo N would always return a
positive result in the range of 0 .. N-1. I'll have to play around with
changing j to an unsigned integer instead. Thanks for your quick response.
 
Jon Skeet said:
It's not being ignored at all. The range for x % y is (-y, y) (note
exclusivity of bounds).

Note that it's the remainder operator, not the modulo operator, which
is why there's the difference. (There's no modulo operator.)

Ah! And that would be the thinko which caused this; thanks for pointing it
out. For the record (and anyone else making the same mistake I did),
changing j to an unsigned integer caused the expression to behave as I
expected it to.
 
Jon,

Actually this is exactly modulo operation according to the latest definition

"According to the newer convention, in general, a mod n is the remainder on
integer division of a by n. Depending on the implementation, the remainder r
is typically constrained to 0 < |r| < |n|, with a negative remainder only
resulting when n < 0."

--

Stoitcho Goutsev (100) [C# MVP]


Jon Skeet said:
Ben Blank said:
I have a loop which iterates over an array in a particular order:

for (j = 0; j < 16; j++) T[(4 - j) % 4] = ...;

The loop proceeds normally for j = 0 through j = 4, but gives an
IndexOutOfRangeException at j = 5. Playing with the watch window seems
to
indicate that the modulo is being completely ignored:

j = 0x5 (int)
T[(4 - j) % 4] = error: index '4-j%4' out of bound for pointer/array 'T'
(4 - j) % 4 = 0xffffffff (int)
4 - j = 0xffffffff (int)
0xffffffff % 4 = 0x3 (long)

I'm stumped. Any ideas?

It's not being ignored at all. The range for x % y is (-y, y) (note
exclusivity of bounds).

Note that it's the remainder operator, not the modulo operator, which
is why there's the difference. (There's no modulo operator.)
 
Stoitcho Goutsev (100) said:
Actually this is exactly modulo operation according to the latest definition

"According to the newer convention, in general, a mod n is the remainder on
integer division of a by n. Depending on the implementation, the remainder r
is typically constrained to 0 < |r| < |n|, with a negative remainder only
resulting when n < 0."

Well, that "typically" certainly isn't the case here (-1 % 2 == -1).

I dare say it depends on what definition you end up using, but it looks
like the OP would expect modulo to give a positive value but
understands that a remainder can be negative.
 
Jon,
Well, that "typically" certainly isn't the case here (-1 % 2 == -1).

n % x = r
-1 % 2 = -1
this is exactly the case

r is negative because n is negative
I dare say it depends on what definition you end up using, but it looks
like the OP would expect modulo to give a positive value but
understands that a remainder can be negative.

Well, I'd expect the result to be positive if the operation was defined only
for positive numbers. In the case it is defined for negative as well I'd
expect negative result
 
Stoitcho Goutsev (100) said:
n % x = r

No, a % n = r, using the terminology above.
-1 % 2 = -1
this is exactly the case

r is negative because n is negative

No it's not - n here is 2, it's a which is -1. Your definition is
talking about situations like 13 % -5.
Well, I'd expect the result to be positive if the operation was defined only
for positive numbers. In the case it is defined for negative as well I'd
expect negative result

Well, not by the definition you were using above, unless n is negative.
 
Well actually now I'm confused. Frankly, I haven't noticed that actually the
definition talks about a % n = r.

If it is the reminder of the integer devision I would say that 13 % -3 = -4
and reminder 1 it looks like the definition has an error it should be that
r < 0 when a < 0
 
Stoitcho Goutsev (100) said:
Well actually now I'm confused. Frankly, I haven't noticed that actually the
definition talks about a % n = r.

If it is the reminder of the integer devision I would say that 13 % -3 = -4
and reminder 1 it looks like the definition has an error it should be that
r < 0 when a < 0

Maybe. It's definitely a matter of definition though - and fortunately,
the C# spec does specify what the results of '%' should be, nice and
clearly :)
 
Maybe. It's definitely a matter of definition though - and fortunately,
the C# spec does specify what the results of '%' should be, nice and
clearly :)

Well, C# specs correctly call % operator 'reminder operator', but "C#
Programmer Reference" which can be found in MSDN call this operator "modulus
operator". Probably this is where the confusion comes from. Mathematicians
probably will find the information in MSDN ambiguous :)

Anyways, everything's clear now
 
Back
Top