1

So I'm trying to implement a more efficient method of calculating 2^n.

I know that you can split it up so that it is O(logn) and it is easy to do using recursion. You keep dividing by 2 and multiply it by the lower power when its odd (or something like that). The problem is I wrote out my multiplication method by hand since its for big numbers. So it needs to return more than one parameter.

One solution I can think of is to make a pair which contains all the needed information. Other than that though I was trying to figure out how to write it using iteration. The only way I can see of doing is using some kind of data structure and then loop through dividing n by 2 and storing the value when n is odd. Then write a for loop and check at each iteration if the value is contained in the data structure. This seems to me like a relatively costly operation.

Is it possible that it would end up less efficient than the recursive version?

I'm doing this because:

  1. I can't get gnp working.
  2. I think I am learning from writing the big numbers class and working with it.
emschorsch
  • 1,619
  • 3
  • 19
  • 33
  • Have you tried a bit-shift? Or do you need this in decimal for very large numbers? – Mysticial Jan 17 '12 at 05:56
  • I'm working with natural numbers only but they need to be precise for numbers as large as 2^100000 currently my program takes 13 seconds for it if the exponent is a power of 2 as the iteration is then simple but otherwise it does the efficient algorithm up to a point and then just starts multiplying by 2 increasing the time taken. – emschorsch Jan 17 '12 at 06:01
  • Related: http://stackoverflow.com/questions/8771713/efficient-exponentiation-for-huge-numbers-im-talking-googols If you want the answer in decimal rather than binary. Then it's more a question of how to efficiently convert from binary to decimal. – Mysticial Jan 17 '12 at 06:08

2 Answers2

6

If you're going to work with big numbers, rather than reinventing the wheel, you probably should take a look at the GNU MP Bignum Library.

Regarding the recursion versus iteration question, the answer is that you can always write them to be equivalent; a recursive function that only calls itself as a tail call is as efficient as a while loop (provided that your compiler supports tail call optimization, but the most common compilers do). For instance, the tail-recursive version of the fast exponentiation function you are describing is (in pseudo-code):

function fastExp(base, exponent, accumulator) {
  if(exponent == 0) {
    return accumulator;
  } else if(exponent % 2 == 0) {
    return fastExp(base * base, exponent/2, accumulator);
  } else {
    return fastExp(base, exponent-1, base * accumulator); 
  }
}

Think of this recursive function as a loop, where the looping condition is exponent != 0, and the recursive calls are like gotos to the beginning of the loop. (You need to call it with accumulator = 1 when you start, by the way.) It is equivalent to the following:

function fastExp(base, exponent) {
  var accumulator = 1;
  while(exponent != 0) {
    if(exponent % 2 == 0) {
      base *= base;
      exponent /= 2;
    } else {
      exponent -= 1;
      accumulator *= base;
    }
  }
  return accumulator;
}

So you can see that they are equivalent, and therefore will perform the same number of operations.

Philippe
  • 9,582
  • 4
  • 39
  • 59
  • Your statement that a recursive function with tail calls is as efficient as a while loop is only true if the compiler optimizes for it. While gcc does, I don't know how common it is in general, given that writing tail-recursive code is not that common in C++. – celtschk Jan 17 '12 at 06:20
  • That's a valid point. gcc does it, Visual Studio does it, LLVM does it. I don't know for sure about the others, but I'd venture to guess that any serious compiler implements that optimization. – Philippe Jan 17 '12 at 06:23
  • Thats nice I should've played around more with exponents to find some rule like this before just coming here and asking this question. I thought of one optimization for my code since I'm using an array I will include an if which tests if accumulator = 1 which will save the time especially if the exponent is a very large power of 2^n. Though I guess the max time saved is twice the number of the digits in the answer (2 loops in my code). – emschorsch Jan 17 '12 at 06:34
0

If you are storing everything as a sequence of 1 s and 0 s..i.e.. in Binary format, 2^n is simply a sequence of 0 s preceded by a single 1 , maybe you can use fact to simply your code

2^1 = 10
2^2 = 100
2^3 = 1000
2^4 = 10000

so on and so forth, Unless this is a learning exercise I would go with a standard arbitrary precision library like what Philippe suggested

parapura rajkumar
  • 24,045
  • 1
  • 55
  • 85