2

Can somewone help me convert this scheme function:

#lang racket
(define (powmod2 x e m)    
  (define xsqrm (remainder (* x x) m))    
  (cond [(= e 0) 1]    
        [(even? e) (powmod2 xsqrm (/ e 2) m)]    
        [(odd? e) (remainder (* x (powmod2 xsqrm (/ (sub1 e) 2) m)) m)]))

Into a function in C, and don't use recursion i.e use iteration.

I'm out of ideas', the part that is bothering me is when e is odd and then the recursive call is in the remainder function. I dont know how to transfer that in a while loop? any tips or suggestions:

This is what i have so far:

int powmod2(int x, int e, int m) {
    int i = x;
    int xsqrm = ((x * x) % m);
    while (e != 0){
        if (e%2 == 0) {
            x = xsqrm;
            e = (e/2);
            xsqrm = ((x * x) % m);
        }
        else {
            i = x; 
            x = xsqrm;
            e = (e - 1)/2;
            xsqrm = ((x * x) % m); 

        }
    }
    e = 1;
    return (i*e)%m;

}
Greg Hewgill
  • 951,095
  • 183
  • 1,149
  • 1,285
Thatdude1
  • 905
  • 5
  • 18
  • 31

5 Answers5

4

The even version is straightforward because the code has been written tail recursively so the call to (powmod2 xsqrm (/ e 2) m) can be expressed iteratively by replacing e with half of e and x with its square modulo m:

int powmod2(int x, int e, int m) { /* version for when e is a power of 2 */
  while ((e /= 2) != 0)
    x = (x * x) % m;
  return x;
}

However the odd version has not been written tail recursively. One approach is to create a helper method that uses an accumulator. This helper method can then be written tail recursively for both even and odd exponent. You can then transform that into an iteration.

Neil
  • 54,642
  • 8
  • 60
  • 72
2

You are having trouble doing the conversion because the original scheme code is not tail recursive. Try to add extra parameters to powmod2 so that you do not need to do the multiplication by remainder in the odd case after calling the recursive function.

To illustrate, its hard to loopify the following function

int fac(n){
    if(n == 0) {
        return 1;
    }else{
        return n * fac(n-1)
    }
}

But it is easy to loopify the version with an accumulation parameter

int fac(n, res){
    if(n == 0) {
        return res;
    }else{
        return fac(n-1, res*n)
    }
}

int real_fac(n){ return fac(n, 1); }
hugomg
  • 68,213
  • 24
  • 160
  • 246
  • So make a helper function that does the "(remainder (* x (powmod2 xsqrm (/ (sub1 e) 2) m)) m)" part? useing iteration? – Thatdude1 Jan 27 '12 at 22:00
  • No you need to modify powmod2 itself and use a helper to start it, as in my fac example. (There might be other ways to solve this simple problem too but then you aren't really doing a direct translation anymore) – hugomg Jan 27 '12 at 22:25
1

Perhaps if you were to run the algorithm with some values to see how the result is calculated, it can help you figure out how to convert it. Let's see a single run for x=5, e=5 and m=7:

1. x=5, e=5, m=7
   xsqrm=4
   e:odd => res = 5*...%7
2. x=4, e=2, m=7
   xsqrm=2
   e:even => res = ...%7
3. x=2, e=1, m=7
   xsqrm=4
   e:odd => res = 2*...%7
4. x=4, e=0, m=7
   e==0 => res = 1

res = 5*2%7=3

At step 1, we get a partial calculation for the result: it is 5 times the result of next step mod 7. At step 2, since it is even the result is the same as the result of the next step. At step 3, we've got something similar to step 1. The result we'll feed upstairs is calculated by multiplying next result by 2 (mod 7 again). And at termination, we've got our result to feed upstairs: 1. Now, as we go up, we just know how to calculate res: 2*1%7 for step 3, 2 for step 2, and 2*5%7 for step 1.

One way to implement it is to use a stack. At every partial result, if the exponent is odd, we can push the multiplication factor to the stack, and once we terminate, we can just multiply them all. This is the naive/cheating method for conversion.

There is a more efficient way that you should be able to see when you look at the steps above. Also other answers about converting everything to tail recursive is a very good hint.

vhallac
  • 13,301
  • 3
  • 25
  • 36
  • Thank you, i did this but did't realize the multiplication of the odd case – Thatdude1 Jan 28 '12 at 05:06
  • Yes, I could see from your code that you got close to the solution. The variable `i` was trying to do the "accumulation" of the result, but fell a little short. And the return value was where you lost the plot a little. :) I hope it's all sorted now. – vhallac Jan 28 '12 at 09:02
1

The easiest way is to reason what is the original function trying to compute? This is the value of x to the power e module m. If you express e in binary, you can get e = e0 * 1 + e1 * 2 + e2 * 4 + e3 * 8 + ..., where en is either 0 or 1. And x^n = x * e0 + x ^ 2 * e1 + x ^ 4 * e2 + x ^ 8 * e3 + ....

By using the mathematical properties of the modulo operator, ie. (a + b) % m = ((a % m) + (b % m)) % m and (a * b) % m = ((a % m) * (b % m)) % m, we can then rewrite the function as:

int powmod2(int x, int e, int m) {
  // This correspond to (= e 0)
  int r = 1;
  while (e != 0) {
    if (e % 2) {
      // This correspond to (odd? e)
      r = (r * x) % m;
    }
    // This correspond to the recursive call
    // that is done whatever the parity of e.
    x = (x * x) % m;
    e /= 2;
  }
  return r;
}
Sylvain Defresne
  • 42,429
  • 12
  • 75
  • 85
  • Thank you, i was wondering why if i add an else for the even case, i would get cpu limit exceeded, also i noticed if i made the even case in the if statement instead of the odd, i would get cpu limit exceeded also – Thatdude1 Jan 28 '12 at 00:21
  • How did you write your code with an else? Did you write `if (e % 2) { r = (r * x) % m; } else { x = (x * x) % m; e /= 2; }`? If you did write that, then if `e` is odd, then you will never decrement it, and enter an infinite loop. If you want to use an `else`, you need to write `if (e % 2) { r = (r * x) % m; x = (x * x) % m; e /= 2; } else { x = (x * x) % m; e /= 2; }`. But then you have the same code at the end of the two branches of the `if` and it is better to remove the `else` completely. – Sylvain Defresne Jan 28 '12 at 00:26
1

The first step would be writing the original Scheme procedure as a tail recursion. Notice that this rewrite works because of the properties of modular arithmetic:

(define (powmod2 x e m)
  (define (iter x e acc)
    (let ((xsqrm (remainder (* x x) m)))
      (cond ((zero? e) acc)
            ((even? e) (iter xsqrm (/ e 2) acc))
            (else (iter xsqrm (/ (sub1 e) 2) (remainder (* x acc) m))))))
  (iter x e 1))

The key element of the above procedure is that the answer is passed in the acc parameter. Now we have a tail recursion, after that the conversion to a fully iterative solution is pretty straightforward:

int powmod2(int x, int e, int m) {
    int acc = 1;
    int xsqrm = 0;
    while (e != 0) {
        xsqrm = (x * x) % m;
        if (e % 2 == 0) {
            x = xsqrm;
            e = e / 2;
        }
        else {
            acc = (x * acc) % m;
            x = xsqrm;
            e = (e - 1) / 2;
        }
    }
    return acc;
}

It can be optimized further, like this:

int powmod2(int x, int e, int m) {
    int acc = 1;
    while (e) {
        if (e & 1) {
            e--;
            acc = (x * acc) % m;
        }
        x = (x * x) % m;
        e >>= 1;
    }
    return acc;
}
Óscar López
  • 232,561
  • 37
  • 312
  • 386