The Power of Recursion

Unlike C/C++, Java, etc. Perl provides an exponentiation operator, **, so $y = $x ** $n calculates $x raised to the $n power. If $n is not an integer, this is undoubtedly calculated using logarithms. If $n is a positive integer, the most straightforward way to calculate the nth power is using a loop:

sub power {
  my( $x, $n ) = @_;
  
  my( $ret_val ) = 1;
  foreach (1..$n) { $ret_val *= $x; }
  return $ret_val;
}

A little experimentation with this will show that it is too slow to be used when $n is large. For example, if $n == 1000 it takes 1000 multiplications.

We can write a faster version using the following two facts that hold when $n is a positive integer:

Putting these together gives the recursive function:

sub power {
  my( $x, $n ) = @_;
  
  if ($n < 1) { return 1; }
  if ($n < 2) { return $x; }
  my( $half_n ) = int( $n / 2 );
  my( $half_power ) = &power( $x, $half_n );
  my( $ret_val ) = $half_power * $half_power;
  if ( $n % 2 == 0 ) { return $ret_val; }
  return $ret_val * $x;
}

When $n == 1000 this only takes 14 multiplications.

Note that there's nothing magic about recursion. The following version is also recursive:

sub power {
   my( $x, $n ) = @_;
   
   if ($n < 1) { return 1; }
   if ($n < 2) { return $x; }
   my( $half_n ) = int( $n / 2 );
   my( $ret_val ) = &power( $x, $half_n ) * &power( $x, $half_n );
   if ( $n % 2 == 0 ) { return $ret_val; }
   return $ret_val * $x;
 }
 
It does just as many multiplications as the version using the loop, and it's even slower due to the added complexity and the overhead of the recursions.