Using Remainder Operator with Negative Divident

V

valentin tihomirov

My rateonale is:
-1 mod 3 = must be 3
0 mod 3 = 0
1 mod 3 = 1
2 mod 3 = 2
3 mod 3 = 3
4 mod 3 = 0
= 1
= 2
= 3
= 0

We note a sequence: 0 1 2 3 0 1 2 3 0 1 2 3. Going in backward direction, we
get 3 2 1 0 3 2 1 0 3 2 1 0.

Since (0 % N) is 0, going one step back (-1 % N) must result in N. But c#
compiler gives me -1. It is wrong. Fix it. The C#LS seems wrong. Correct it.
 
J

Jon Skeet [C# MVP]

valentin tihomirov said:
My rateonale is:
-1 mod 3 = must be 3
0 mod 3 = 0
1 mod 3 = 1
2 mod 3 = 2
3 mod 3 = 3
4 mod 3 = 0
= 1
= 2
= 3
= 0

We note a sequence: 0 1 2 3 0 1 2 3 0 1 2 3. Going in backward direction, we
get 3 2 1 0 3 2 1 0 3 2 1 0.

Since (0 % N) is 0, going one step back (-1 % N) must result in N. But c#
compiler gives me -1. It is wrong. Fix it. The C#LS seems wrong. Correct it.

Your understanding of "remainder" is too rigid. Fix it :)

Seriously, there are different understandings of how remainders should
work with negative numbers. Some systems use the sign of the dividend,
others use the sign of the divisor. See
http://en.wikipedia.org/wiki/Modulo_operation for a list.

You know what I think is *really* broken? To leave it to the
implementation - which is what C++ did, at least at the time of
Stroustrup's 2nd edition. (I seriously hope it's been fixed since
then.)


(I have in my head that "remainder" should work as shown in C#, but if
a language defines a "modulo" operator, that should always be non-
negative. However, I can't find any evidence backing that up.)
 
D

Doug Semler

(I have in my head that "remainder" should work as shown in C#, but if
a language defines a "modulo" operator, that should always be non-
negative. However, I can't find any evidence backing that up.)


What should be non-negative? The result of the modulus operator? If the
dividend is negative in C#, the result of the modulus is negative, which
actually makes sense mathematically (what would you need to ADD to the
result of the divisor times the result of the division to get back to your
dividend?) Note this is only for integer modulus. I always hated float
modulus :)

-3 / -2 = 1 - what would you need to add? (-1) so -3 % -2 = -1
-3 / 2 = -1 - what do you add? -1 again. so -3 % 2 = -1
3 / -2 = -1 - what do you need to add to -1 * -2?


--
Doug Semler, MCPD
a.a. #705, BAAWA. EAC Guardian of the Horn of the IPU (pbuhh).
The answer is 42; DNRC o-
Gur Hfrarg unf orpbzr fb shyy bs penc gurfr qnlf, abbar rira
erpbtavmrf fvzcyr guvatf yvxr ebg13 nalzber. Fnq, vfa'g vg?
 
D

Doug Semler

Doug Semler said:
What should be non-negative? The result of the modulus operator? If the
dividend is negative in C#, the result of the modulus is negative, which
actually makes sense mathematically (what would you need to ADD to the
result of the divisor times the result of the division to get back to your
dividend?) Note this is only for integer modulus. I always hated float
modulus :)

Note that my note above was for the example below, not that float modulus
acted differently with respect to sign said:
-3 / -2 = 1 - what would you need to add? (-1) so -3 % -2 = -1
-3 / 2 = -1 - what do you add? -1 again. so -3 % 2 = -1
3 / -2 = -1 - what do you need to add to -1 * -2?

--
Doug Semler, MCPD
a.a. #705, BAAWA. EAC Guardian of the Horn of the IPU (pbuhh).
The answer is 42; DNRC o-
Gur Hfrarg unf orpbzr fb shyy bs penc gurfr qnlf, abbar rira
erpbtavmrf fvzcyr guvatf yvxr ebg13 nalzber. Fnq, vfa'g vg?
 
J

Jon Skeet [C# MVP]

Doug Semler said:
What should be non-negative? The result of the modulus operator?

Yes - in my head, anyway :)
If the dividend is negative in C#, the result of the modulus is negative, which
actually makes sense mathematically (what would you need to ADD to the
result of the divisor times the result of the division to get back to your
dividend?) Note this is only for integer modulus. I always hated float
modulus :)

Yes, I totally see your point. Of course, it depends on how you round
the division aspect. If you define integer division to round down, i.e.
to always return the largest number d such that d*x < y, then you will
always have a non-negative integer r such that d*x+r = y. However, C#
(and many other computer languages) use round-towards-zero for
division, which is where the negative remainder comes in.

At least, that's what I currently think - but I'm about to go to bed,
so anything I write now probably shouldn't be trusted.
 
V

valentin tihomirov

Your understanding of "remainder" is too rigid. Fix it :)

:) You do not understand. THIS IS REQUIREMENT OF MY PROGRAM!


This math is required for Rayal Mail
http://emce.gov.uk/documents/publications/royal_mail/4) Royal Mail Cleanmail Brochure.pdf
checksum character computation. They map chars (0 1 2 3 4 5 ...) to
increments (1 2 3 4 5 0) by (i + 1) % 6. Afterwards, the sum is divided by 6
and the index (0 1 2 3 4 5 ...) must be reporduced from the reminder (1 2 3
4 5 0 ...). In order for the math to work, the reverse operation (sum - 1) %
6 must treat the last column 0 as 6 resulting in char 5.
 
J

Jon Skeet [C# MVP]

:) You do not understand. THIS IS REQUIREMENT OF MY PROGRAM!

So write a method to behave how you want it to, rather than trying to
force the rest of us to change.

The following probably isn't the cleanest way of doing it, but it's
incredibly simple (assuming a positive divisor - when the divisor is
negative, I don't know what you'd want to do).

public static int Modulus (int dividend, int divisor)
{
int remainder = dividend % divisor;
return remainder >= 0 ? remainder : remainder+divisor;
}
This math is required for Rayal Mail
http://emce.gov.uk/documents/publications/royal_mail/4) Royal Mai...
checksum character computation. They map chars (0 1 2 3 4 5 ...) to
increments (1 2 3 4 5 0) by (i + 1) % 6. Afterwards, the sum is divided by 6
and the index (0 1 2 3 4 5 ...) must be reporduced from the reminder (1 2 3
4 5 0 ...). In order for the math to work, the reverse operation (sum - 1) %
6 must treat the last column 0 as 6 resulting in char 5.

So you expect a language to change to support a single use case which
doesn't seem terribly well thought out? I'm afraid I have very little
sympathy for that position. Work round it - it's trivial to do so.

Jon
 
V

valentin tihomirov

Jon Skeet said:
So write a method to behave how you want it to, rather than trying to
force the rest of us to change.

The following probably isn't the cleanest way of doing it, but it's
incredibly simple (assuming a positive divisor - when the divisor is
negative, I don't know what you'd want to do).

public static int Modulus (int dividend, int divisor)
{
int remainder = dividend % divisor;
return remainder >= 0 ? remainder : remainder+divisor;
}


So you expect a language to change to support a single use case which
doesn't seem terribly well thought out? I'm afraid I have very little
sympathy for that position. Work round it - it's trivial to do so.

Jon

Actually, I have determined that their algorithm can be implemented without
wrapping the last column to 0 forth and back, which require these ugly
if-else. It is the Royal Mail User Guide, which must be fixed then
(simplified).
 
J

Jon Skeet [C# MVP]

Actually, I have determined that their algorithm can be implemented without
wrapping the last column to 0 forth and back, which require these ugly
if-else. It is the Royal Mail User Guide, which must be fixed then
(simplified).

I'd prefer their algorithm to be fixed - keep the content of the table
where it is, but make 0 the first row/column. Too late to do that now,
but clearly you can remap the table if you're willing to change where
the contents are. It's only a lookup, after all.

Jon
 
V

valentin tihomirov

I'd prefer their algorithm to be fixed - keep the content of the table
where it is, but make 0 the first row/column. Too late to do that now,
but clearly you can remap the table if you're willing to change where
the contents are. It's only a lookup, after all.

The algorithm seems correctly designed. The explanation is bad moving the 0
column into the end and back for no reason.
 
J

Jon Skeet [C# MVP]

The algorithm seems correctly designed. The explanation is bad moving the 0
column into the end and back for no reason.

Yes, by "algorithm" I guess I really meant "data used by the
algorithm" - i.e. the table.

Either way, it's certainly not C#'s fault :)

Jon
 
J

james.curran

You know what I think is *really* broken? To leave it to the
implementation - which is what C++ did, at least at the time of
Stroustrup's 2nd edition. (I seriously hope it's been fixed since
then.)

I doubt it. Especially considering the C++ standard still does not
require a particular binary representation for -1, or, for that
matter, a particular value for 32767+1.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top