Fast Exponentiation by Squaring
Fast exponentiation using at most 2 * log₂(n) multiplications, with a partial forward.
When dealing with large exponents, the naive implementation is inefficient. To enhance performance, an alternative approach called Exponentiation by Squaring is commonly used. This method has several implementations.
One of these methods consists of recursive calls to the function with computation based on n:
- If n equals to 0, stop the loop and return base
- If n is even, square base and divide n by 2, that is, return
<function> (base * base, n / 2): this corresponds to calculate2^6as4^3 - If n is odd, multiply the result by the base and reduce e by 1,
that is, return
base * <function> (base, n – 1): this corresponds to calculate2^3as2 * 2^2
This Exponentiation by Squaring algorithm requires a maximum of 2 * log₂(n) iterations for computation, which is significantly fewer than the n iterations needed in previous algorithms.
To implement this algorithm, we need a forward block to perform a loop, as recursive logic cannot be used in safety-critical embedded systems, and local variables (or output values) for the current value of the base, the exponent, and the final value to return.
A forward block iterates as a loop-like construct over arrays of values or ranges of numbers and can return any number of outputs that could be scalar values or arrays. Moreover, while the body of the fold operator contains an operator, the body of the forward block is a scope, allowing more complex modeling.
A forward iteration can be stopped under a condition before the last step has been reached: this is called partial forward.
To implement our algorithm, we use a forward until (that is, partial forward) with:
| Number of iterations |
We have a maximum of 2 * log2(maximum representable integer for exponent) iterations. As we want to support 64-bits integers, we set the number of iterations to 2 * 64 = 128 |
| Local variables | We set 2 local variables in the scope of the forward block: e and b, representing respectively the current values of the exponent (initialized to n with a last) and base (initialized to base with a last). |
| Stop condition (until) | We stop the loop when the current value of exponent, e, is null. |
| Output value |
We use a return value result, initialized to 1. Moreover, for a forward until, the first output value corresponds to the number of iteration steps that were executed. As we are not interested in this value, we assign the 2nd output value of the forward block to the output of our function. |
| Body for the forward block |
We implement the body using an ActivateIf block with 2 cases based on oddness/evenness of e:
Each case of the ActivateIf corresponds to a specific scope. In each scope, we require access to the values of variables e, b, and result from the previous iteration. The pre keyword may seem like a viable solution; however, it only retrieves the last value set within the given scope, resulting in the same value being referenced throughout the entire loop if it is not modified in the scope (that is, the value of b in the case where e is odd). Instead, we can utilize the last keyword, which enables us to access the values of the previous iterations and correctly reference the desired variables. So, for example, in the case where e is odd, we have result = last ‘result * last ‘b. |
function FastExp (base: 'T; n: 'U;)
returns (y: 'T;)
where 'T numeric
where 'U unsigned 
The forward block defines the following local variables:
e: 'U last = nb: 'T last = base
| Pros | Cons |
|---|---|
| Condition check at each cycle: a computation time is required to check the until clause at each iteration |