Mathematical modulus in c#
Asked Answered
P

9

35

Is there a library function in c# for the mathematical modulus of a number - by this I specifically mean that a negative integer modulo a positive integer should yield a positive result.

edited to provide an example:

-5 modulo 3 should return 1

Pompous answered 22/4, 2010 at 13:10 Comment(1)
See https://mcmap.net/q/100199/-modulo-operation-with-negative-numbers for a method that has less overflow problems.Scrubby
A
30

Try (a % b) * Math.Sign(a)

Try this; it works correctly.

static int MathMod(int a, int b) {
    return (Math.Abs(a * b) + a) % b;
}
Anhwei answered 22/4, 2010 at 13:12 Comment(7)
This gives -5%4 = 1, but it should be 3.Bloodshed
+1 for being the first to post a correct algorithm (but watch out for overflow!). To strictly answer his question, though, no, there's nothing built into the framework for this.Bloodshed
much better than the no-brains-required while (a < 0) {a += b;}Pompous
Accepted as the first correct algorithm, but I think I am more likely to use ((a % b) + b) % bPompous
the Math.Abs is very slow in this implementation, ((a % b) + b) % b is the fastest in my benchmarks using c# .net 4.Oviposit
warning of overflow with this method !!Hepta
The only thing I would change is the names of the variables to dividend and divisor respectively, similarly to arduino.cc/en/Reference/ModuloRavelin
G
8
x < 0 ? ((x % m) + m) % m : x % m;
Governance answered 22/4, 2010 at 13:26 Comment(5)
Why use the ternary operator?Pompous
@penguat: Because if x is non-negative then there is no reason to go through the extra work.Governance
I'm not sure which is more work on average, the conditional or the fixed addition and modulus, not that it matters in my case. This answer is correct, anyway. Thanks.Pompous
@penguat: Hard to say; I always consider division and modulus operations to be relatively expensive (unless they are trivial, as in divide by 2 or mod 2). I imagine the overhead of the ternary operator is only a few cycles for the check and jumps. Plus, there is no chance for overflow with non-negative x in this computation. However, without the ternary operator, you could overflow if x = 1 and m = int.MaxValue (or in any scenario where 0 < x < m and x + m > int.MaxValue).Governance
I would definitely guess that the extra modulo is faster than the branch on modern processors. However, I've never tested it, so I don't really know. Also, it's a pretty slight distinction. I'm not sure which is more readable. I was going to say without the ternary operator at first, but when I think about it that x < 0 does tell the reader why we're doing something fancy without having the need for a comment.Brannen
P
4

Well the definition (if I'm not mistaken) is something like this

a mod b = a - b * floor(a/b)

It's probably pretty slow and beware of integer division just like built in modulus :)

Other option is to modify the result of built-in modulus according to the signs of operands. Something like this:

if(a < 0 && b > 0)
{
    return (a % b + b) % b;
}
else if ....
Prostration answered 22/4, 2010 at 13:26 Comment(0)
C
2
a < 0 ? ((a+1)%b + b-1) : (a%b);

That requires only one % operation (and one ternary op) and no multiplication

Creighton answered 29/11, 2010 at 12:1 Comment(0)
B
1

If you're using any of these algorithms and you need to do division also, don't forget to make sure that you subtract 1 when appropriate.

I.e.,

if -5 % 2 = -1 and -5 / 2 = -2, and if you care that -5 / 2 * 2 + -5 % 2 = -5, then when you calculate -5 % 2 = 1, that you also calculate -5 / 2 = -3.

Brannen answered 23/4, 2010 at 1:25 Comment(2)
I'm not quite sure what you're getting at here... I'd normally preserve the original number rather than try to reconstruct it.Pompous
I'm not suggesting you reconstruct it. I was just concerned that your algorithm might use the / operator as well and depend on them being consistent.Brannen
K
0

Fix :

(ans=a%b)<0 ? (a<0 && b<0 ? (ans-b)%(-b) : (ans+b)%b) : ans

Klara answered 22/4, 2010 at 16:44 Comment(2)
what about -10 mod 3? your solution would give -1 where the required answer is 2.Pompous
@Pompous a=-10 , b=3 ans= -1 < 0 , so solution = (-1+3) % 3 =2 what's wrong ?Klara
T
0

I know the question didn't ask for it, but I just wrote and tested a method which returns the quotient as well. Didn't find this when I was looking for it, so I thought I'd put it out there.

/// <summary>
/// Compute integer quotient and remainder of <paramref name="dividend"/> / <paramref name="divisor"/>
/// where the <paramref name="remainder"/> has the same sign as <paramref name="divisor"/>, and is
/// between zero (inclusive) and the <paramref name="divisor"/> (exclusive). As always,
/// (quotientResult * <paramref name="divisor"/> + <paramref name="remainder"/> == <paramref name="dividend"/>).
/// </summary>
public static int DivRemPeriodic(int dividend, int divisor, out int remainder) {
    var quotient = Math.DivRem(dividend, divisor, out remainder);
    if (divisor > 0 ? remainder < 0 : remainder > 0) {
        remainder += divisor;
        quotient -= 1;
    }
    return quotient;
}
Toronto answered 22/8, 2013 at 16:6 Comment(2)
The remainder here is equivalent to the modulus I was asking for - with the quotient as well. This may have a different result for divisors less than zero.Pompous
Doh! Yep, I meant "returns the quotient as well." Corrected. It works for negative divisors with result as given in the comment doc. Remainder (aka "modulus") will have same sign as divisor. For a negative divisor, the modulus is periodic over the range (-divisor,0].Toronto
V
0

The modulus operation is the reminder of a division and this exists in Math:

double module = Math.IEEERemainder(x, y);
Valor answered 17/1 at 18:51 Comment(1)
Modulus is not the same as remainder, it's just unfortunate naming in programming. Modulus and remainder do partially overlap - i.e. produce the same result for many numbers, but not all. (Also the method you posted is specifically for floating-point numbers, which is slightly different.)Scrubby
R
-3

Might be the % operator?

http://msdn.microsoft.com/en-us/library/0w4e0fzs.aspx

Reichstag answered 22/4, 2010 at 13:12 Comment(2)
No this doesn't yield a positive result when doing -5 % 2Bowker
He wants -5 % 2 to be +1, not -1.Anhwei

© 2022 - 2024 — McMap. All rights reserved.