1

I am carrying out the following modulo division operations from within a C program:

(5^6) mod 23 = 8

(5^15) mod 23 = 19

I am using the following function, for convenience:

int mod_func(int p, int g, int x) {
    return ((int)pow((double)g, (double)x)) % p;
}

But the result of the operations when calling the function is incorrect:

mod_func(23, 5, 6) //returns 8
mod_func(23, 5, 15) //returns -6

Does the modulo operator have some limit on the size of the operands?

1
  • 1
    You are overflowing the int into a negative value. The modulus of a negative number will be negative. Commented Dec 19, 2012 at 21:59

4 Answers 4

3

5 to the power 15 is 30,517,578,125

The largest value you can store in an int is 2,147,483,647

You could use 64-bit integers, but beware you'll have precision issues when converting from double eventually.

From memory, there is a rule from number theory about the calculation you are doing that means you don't need to compute the full power expansion in order to determine the modulo result. But I could be wrong. Been too many years since I learned that stuff.

Ahh, here it is: Modular Exponentiation

Read that, and stop using double and pow =)

int mod_func(int p, int g, int x)
{
    int r = g;
    for( int i = 1; i < x; i++ ) {
        r = (r * g) % p;
    }
    return r;
}
Sign up to request clarification or add additional context in comments.

2 Comments

The largest value you can store in an int is 2,147,483,647 -- if int is 32 bits, which is common but not universal.
I feel stupid for not thinking about the maximum integer size. All is well now - glad you brought up this method!
3

The integral part of pow(5, 15) is not representable in an int (assuming the width of int is 32-bit). The conversion (from double to int in the cast expression) is undefined behavior in C and in C++.

To avoid undefined behavior, you should use fmod function to perform the floating point remainder operation.

Comments

1

My guess is the problem is 5 ^ 15 = 30517578125 which is greater than INT_MAX (2147483647). You are currently casting it to an int, which is what's failing.

Comments

0

As has been said, your first problem in

int mod_func(int p, int g, int x) {
    return ((int)pow((double)g, (double)x)) % p;
}

is that pow(g,x) often exceeds the int range, and then you have undefined behaviour converting that result to int, and whatever the resulting int is, there is no reason to believe it has anything to do with the desired modulus.

The next problem is that the result of pow(g,x) as a double may not be exact. Unless g is a power of 2, the mathematical result cannot be exactly represented as a double for large enough exponents even if it is in range, but it could also happen if the mathematical result is exactly representable (depends on the implementation of pow).

If you do number-theoretic computations - and computing the residue of a power modulo an integer is one - you should only use integer types.

For the case at hand, you can use exponentiation by repeated squaring, computing the residue of all intermediate results. If the modulus p is small enough that (p-1)*(p-1) never overflows,

int mod_func(int p, int g, int x) {
    int aux = 1;
    g %= p;
    while(x > 0) {
        if (x % 2 == 1) {
            aux = (aux * g) % p;
        }
        g = (g * g) % p;
        x /= 2;
    }
    return aux;
}

does it. If p can be larger, you need to use a wider type for the calculations.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.