Most programming languages have a built-in implementation of exponentiation.



Task

Re-implement integer exponentiation for both   intint   and   floatint   as both a procedure,   and an operator (if your language supports operator definition).

If the language supports operator (or procedure) overloading, then an overloaded form should be provided for both   intint   and   floatint   variants.



Related tasks

   Exponentiation order
   arbitrary-precision integers (included)
   Exponentiation with infix operators in (or operating on) the base


object Exponentiation {
  import scala.annotation.tailrec
 
  @tailrec def powI[N](n: N, exponent: Int)(implicit num: Integral[N]): N = {
    import num._
    exponent match {
      case 0 => one
      case _ if exponent % 2 == 0 => powI((n * n), (exponent / 2))
      case _ => powI(n, (exponent - 1)) * n
    }
  }
 
  @tailrec def powF[N](n: N, exponent: Int)(implicit num: Fractional[N]): N = {
    import num._
    exponent match {
      case 0 => one
      case _ if exponent < 0 => one / powF(n, exponent.abs)
      case _ if exponent % 2 == 0 => powF((n * n), (exponent / 2))
      case _ => powF(n, (exponent - 1)) * n
    }
  }
 
  class ExponentI[N : Integral](n: N) {
    def \u2191(exponent: Int): N = powI(n, exponent)
  }
 
  class ExponentF[N : Fractional](n: N) {
    def \u2191(exponent: Int): N = powF(n, exponent)
  }
 
  object ExponentI {
    implicit def toExponentI[N : Integral](n: N): ExponentI[N] = new ExponentI(n)
  }
 
  object ExponentF {
    implicit def toExponentF[N : Fractional](n: N): ExponentF[N] = new ExponentF(n)
  }
 
  object Exponents {
    implicit def toExponent(n: Int): ExponentI[Int] = new ExponentI(n)
    implicit def toExponent(n: Double): ExponentF[Double] = new ExponentF(n)
  }
}