7

I need to be able to calculate (a^b) % c for very large values of a and b (which individually are pushing limit and which cause overflow errors when you try to calculate a^b). For small enough numbers, using the identity (a^b)%c = (a%c)^b%c works, but if c is too large this doesn't really help. I wrote a loop to do the mod operation manually, one a at a time:

private static long no_Overflow_Mod(ulong num_base, ulong num_exponent, ulong mod) 
    {
        long answer = 1;
        for (int x = 0; x < num_exponent; x++)
        {
            answer = (answer * num_base) % mod;
        }
        return answer;
    }

but this takes a very long time. Is there any simple and fast way to do this operation without actually having to take a to the power of b AND without using time-consuming loops? If all else fails, I can make a bool array to represent a huge data type and figure out how to do this with bitwise operators, but there has to be a better way.

Gumbo
  • 643,351
  • 109
  • 780
  • 844
  • 2
    Sounds like an Euler problem... If it is, you should clearly state that in the question instead of trying to cheat... – Guffa Jun 12 '09 at 17:51
  • Knowing the range of a, b, and c might help us. – Nosredna Jun 12 '09 at 17:52
  • This bool array idea is not going to work. Bool arrays are not bitvectors, and they are not stored packed. Plus, then you're not relying on direct hardware math. – Matthew Flaschen Jun 12 '09 at 17:57
  • I don't know if it's really cheating. Reading about that problem it looks like he knows the answer he just wants to know how to do it within reasonable time constraints in c#. – Rich Schuler Jun 12 '09 at 18:13
  • 1
    I actually wasn't trying to solve that problem at all, I need this algorithm for an encryption program I'm writing. –  Jun 12 '09 at 22:03
  • 3
    Is this for your own edification, or are you planning on actually relying upon your algorithm to protect your customers from evildoers? If the former, you go. If the latter, I strongly urge you to reconsider. – Eric Lippert Jun 12 '09 at 23:20

11 Answers11

9

I guess you are looking for : http://en.wikipedia.org/wiki/Montgomery_reduction or the simpler way based on Modular Exponentiation (from wikipedia)

Bignum modpow(Bignum base, Bignum exponent, Bignum modulus) {

    Bignum result = 1;

    while (exponent > 0) {
        if ((exponent & 1) == 1) {
            // multiply in this bit's contribution while using modulus to keep result small
            result = (result * base) % modulus;
        }
        // move to the next bit of the exponent, square (and mod) the base accordingly
        exponent >>= 1;
        base = (base * base) % modulus;
    }

    return result;
}
Ryan Oberoi
  • 13,817
  • 2
  • 24
  • 23
  • If the modulus is smaller than the exponent, I think you could improve this algorithm by taking the modulus of the count of 1 bits of the exponents and only do that many loop iterations. One could actually do even better than that in some cases. See Kai's answer. – Brian Jun 12 '09 at 18:22
  • i think you can break out whenever result = 0 result = (result * base) % modulus; if (result == 0) break; – johnnycrash Jun 12 '09 at 19:23
  • The formatting screwed up my comment. Add "if (result == 0) break;" after the calculation of result. – johnnycrash Jun 12 '09 at 19:24
  • Actually before you mutliply result*base, check base==0 and break then. – johnnycrash Jun 12 '09 at 19:25
  • You can break out at the bottom after "exponent >>= 1;" if exponent == 0 and avoid having to do the last mulitply and mod. – johnnycrash Jun 12 '09 at 19:40
  • adding the `if (exponent == 0) break;` actually slows it down slightly in a ulong implementation - running a long prime test takes 32.798 without it and 32.733 with it after on second run; testing base is slightly slower and testing result is quite a bit slower (about 33 seconds). Sometimes shortcuts aren't optimizations. – NetMage Mar 14 '17 at 21:48
6

Fast Modular Exponentiation (I think that's what it's called) might work.

Given a, b, c and a^b (mod c):

1. Write b as a sum of powers of 2. (If b=72, this is 2^6 + 2^3 )
2. Do:
    (1) a^2 (mod c) = a*
    (2) (a*)^2 (mod c) = a*
    (3) (a*)^2 (mod c) = a*
    ...
    (n) (a*)^2 (mod c) = a*

3. Using the a* from above, multiply the a* for the powers of 2 you identified. For example:
    b = 72, use a* at 3 and a* at 6.
    a*(3) x a*(6) (mod c)

4. Do the previous step one multiplication at a time and at the end, you'll have a^b % c.

Now, how you're going to do that with data types, I don't know. As long as your datatype can support c^2, i think you'll be fine.

If using strings, just create string versions of add, subtract, and multiply (not too hard). This method should be quick enough doing that. (and you can start step 1 by a mod c so that a is never greater than c).

EDIT: Oh look, a wiki page on Modular Exponentiation.

apandit
  • 3,304
  • 1
  • 26
  • 32
4

Here's an example of Fast Modular Exponentiation (suggested in one of the earlier answers) in java. Shouldn't be too hard to convert that to C#

http://www.math.umn.edu/~garrett/crypto/a01/FastPow.html

and the source...

http://www.math.umn.edu/~garrett/crypto/a01/FastPow.java

Jason Braucht
  • 2,358
  • 19
  • 31
2

Python has pow(a,b,c) which returns (a**b)%c (only faster), so there must be some clever way to do this. Maybe they just do the identity you mentioned.

Nosredna
  • 83,000
  • 15
  • 95
  • 122
1

Short of writing your own fast modular exponentiation, the simplest idea I can come up with, is to use the F# BigInt type: Microsoft.FSharp.Math.Types.BigInt which supports operations with arbitrarily large scale - including exponentiation and modular arithmetic.

It's a built-in type that will be part of the full .NET framework with the next release. You don't need to use F# to use BitInt - you can make use of it directly in C#.

LBushkin
  • 129,300
  • 32
  • 216
  • 265
1

I'd recommend checking over the Decimal documentation and seeing if it meets your requirements since it is a built in type and can use the mod operator. If not then you're going to need an arbitrary precision library like java's Bignum.

Rich Schuler
  • 41,814
  • 6
  • 72
  • 59
  • no shit, i was saying like, as in he would need to find an equivalent. way to not read. – Rich Schuler Jun 12 '09 at 17:48
  • He said *like* Java's Bignum. Not *use" Java's Bignum. Given that he knows about C#'s decimal type, it's probably a good bet that he knows the question is about C#. – Tim Lesher Jun 12 '09 at 17:49
1

You could try this:

C#: Doing a modulus (mod) operation on a very large number (> Int64.MaxValue)
http://www.del337ed.com/blog/index.php/2009/02/04/c-doing-a-modulus-mod-operation-on-a-very-large-number-int64maxvalue/

Robert Harvey
  • 178,213
  • 47
  • 333
  • 501
ChristopheD
  • 112,638
  • 29
  • 165
  • 179
1

You can try factoring 'a' into sufficiently small numbers.

If the factors of 'a' are 'x', 'y', and 'z', then

a^b = (x^b)(y^b)(z^b).

Then you can use your identity: (a^b)%c = (a%c)^b%c

Robert Cartaino
  • 27,494
  • 6
  • 45
  • 67
  • Except that factoring is a much more difficult problem than modulus – Eclipse Jun 12 '09 at 19:27
  • I would just start out dividing a/2 in a loop until it didn't divide evenly.... Then a/3, etc with prime numbers until 'a' was "sufficiently small" for a^b not to overflow. Then complete the operation as outlined by the original poster. – Robert Cartaino Jun 13 '09 at 00:07
1

It seems to me like there's some kind of relation between power and mod. Power is just repeated multiplication and mod is related to division. We know that multiplication and division are inverses, so through that connection I would assume there's a correlation between power and mod.

For example, take powers of 5:

5 % 4 = 1
25 % 4 = 1
125 % 4 = 1
625 % 4 = 1
...

The pattern is clear that 5 ^ b % 4 = 1 for all values of b.

It's less clear in this situation:

5 % 3 = 2
25 % 3 = 1
125 % 3 = 2
625 % 3 = 1
3125 % 3 = 2
15625 % 3 = 1
78125 % 3 = 2
...

But there's still a pattern.

If you could work out the math behind the patterns, I wouldn't be surprised if you could figure out the value of the mod without doing the actual power.

Kai
  • 9,444
  • 6
  • 46
  • 61
0

Can you factor a, b, or c? Does C have a known range?

These are 32 bit integers! Go check this site

For instance, here is how you get the mod of n%d where d 1>>s (1,2,4,8,...)

  int n = 137;     // numerator
  int d = 32;      // denom d will be one of: 1, 2, 4, 8, 16, 32, ...
  int m;           // m will be n % d
  m = n & (d - 1); 

There is code for n%d where d is 1>>s - 1 (1, 3, 7, 15, 31, ...)

This is only going to really help if c is small though, like you said.

johnnycrash
  • 5,184
  • 5
  • 34
  • 58
-2

Looks like homework in cryptography.

Hint: check out Fermat's little theorem.

Tobias
  • 6,388
  • 4
  • 39
  • 64