Is there any efficient way to compute the exponentiation of an fractional base and fractional exponent?

First off - not the same question as this (which is great). I need the exponent to be fractional as well. Something like 2.5^0.75

The code of a good solution:

function power(uint256 _baseN, uint256 _baseD, uint32 _expN, uint32 _expD) internal view returns (uint256, uint8) {
assert(_baseN < MAX_NUM);

uint256 baseLog;
uint256 base = _baseN * FIXED_1 / _baseD;
if (base < OPT_LOG_MAX_VAL) {
baseLog = optimalLog(base);
}
else {
baseLog = generalLog(base);
}

uint256 baseLogTimesExp = baseLog * _expN / _expD;
if (baseLogTimesExp < OPT_EXP_MAX_VAL) {
return (optimalExp(baseLogTimesExp), MAX_PRECISION);
}
else {
uint8 precision = findPositionInMaxExpArray(baseLogTimesExp);
return (generalExp(baseLogTimesExp >> (MAX_PRECISION - precision), precision), precision);
}
}

Some explanation

A floating point number x can be represented in two numbers: a/b

if x = a/b and y = c/d, then x ^ y = (a/b) ^ (c/d)

The problem

The problem is that if the a code is written as (a/b) ^ (c/d), the accuracy of the result would be a mess. Because the division of a/b and c/d would smash the floating point.

Going into another try, the expression (a/b) ^ (c/d) could be evaluated as a ^ (c/d) / b ^ (c/d) or (a^c + a^(1/d)) / (b^c + b^(1/d)). The problem with this is that the powering a to c or even to c/d could easily overflow uint256! Even though, the final resulting value could be a small uint8. (this is explained here)

The Solution

There is an approximation for x ^ y as follow:

x ^ y  = e ^ (log(x) * y)

Actually, the method above depend on this equation to compute the power function. As follow:

(_baseN / _baseD) ^ (_expN /_expD) = e ^ (log(base) * exp)

Where base = _baseN / _baseD (note that FIXEX_1 that is used in the code, is just used to shift the number of left in order to provide better accuracy of the division. And exp = _expN /_expD.

The key point here is calculating the log(base) * exp before powering to e, will prevent overflow compared to the early discussed formula the can easily produce overflow: a ^ (c/d) / b ^ (c/d) or (a^c + a^(1/d)) / (b^c + b^(1/d)).

However, for optimalLog vs. generalLog and optimalExp vs. generalExp that is used in the provided code, they is about calculating the log and e ^ either in an optimal or an approximate calculation.

Thanks leonprou for his valuable comments on the question.

• I gave you the check mark but you've removed some of the functions. Could you please include those so that this compiles? – ZMitton Jun 20 '18 at 16:11
• I did not include the full code in the answer because it is quite long with 350+ lines of code. However, upon your request I created a file that contains only and all the needed functions at github.com/Muhammad-Altabba/solidity-toolbox/blob/master/… . – Muhammad Altabba Jun 20 '18 at 18:23

You may calculate x^y as 2^(y log_2 x) using ABDK Math 64.64 library, that has both: 2^x and log_2 x functions implemented for binary fixed point numbers. This way is especially efficient in case you need to calculate x^y multiple times for the same x but different y, because you may calculate log_2 x once and reuse.