#include <assert.h> // assert
#include <float.h> // FLT_RADIX, DBL_MANT_DIG
#include <iomanip>
#include <iostream>
#include <limits.h> // CHAR_BIT
#include <math.h> // floor
using namespace std;
#define STATIC_ASSERT( e ) \
typedef char StaticAssert[(e)? 1 : -1];
int const bitsPerByte = CHAR_BIT;
int const logHighestIntN = sizeof( int )*bitsPerByte - 2;
int const highestIntN = 1 << logHighestIntN;
bool isInteger( double const x ) { return (x - floor( x ) == 0); }
int pow4( int const x ) { return x*x*x*x; }
int pow8( int const x ) { return pow4( x*x ); }
double root( double const n, double x )
{
assert( n > 0 );
assert( isInteger( n ) );
return pow( x, 1.0/n ); // TODO
}
// Returns x^(2^logN)
double expPower( double const x, int const logN )
{
assert( logN >= 0 );
double result = x;
for( int i = 1; i <= logN; ++i )
{
result *= result;
}
return result;
}
#if 0
double intPower( double const x, int const n )
{
assert( n >= 0 );
if( n == 0 )
{
return 1;
}
else if( n % 2 == 1 )
{
return x*intPower( x, n - 1 );
}
else
{
return intPower( x*x, n/2 );
}
}
#else
double intPower( double const x, int const n )
{
assert( n >= 0 );
int bitmask = 1;
for( int i = n; i != 0; i >>= 1 )
{
bitmask <<= 1;
}
// bitmask now has a 1 bit in the most significant bit pos of n.
double result = 1.0;
for( ;; )
{
int const bit = (n & bitmask);
if( bit != 0 ) { result *= x; }
bitmask = (bitmask >> 1);
if( bitmask == 0 ) { break; }
result *= result;
}
return result;
}
#endif
double fractionalPower( double const x, double const n )
{
wclog << "fractionalPower(" << x << ", " << n << ")" << endl;
assert( 0 < n && n < 1 );
STATIC_ASSERT( FLT_RADIX == 2 );
int const radix = pow4( FLT_RADIX );
int const nDigits = DBL_MANT_DIG/4;
double result = 1.0;
double digitWeight = 1.0;
double digits = n;
for( int i = 1; i <= nDigits && digits != 0; ++i )
{
double const leftShiftedDigits =
radix*digits;
int const digit =
static_cast<int>( floor( leftShiftedDigits ) );
digitWeight *= radix;
double const multiplier =
root( digitWeight, intPower( x, digit ) );
result *= multiplier;
wclog << "!" << setprecision( 17 ) << result << endl;
digits = leftShiftedDigits - digit;
}
return result;
}
double integralPower( double const x, double const n )
{
wclog << "integralPower(" << x << ", " << n << ")" << endl;
assert( n >= 0 );
assert( isInteger( n ) );
if( n > highestIntN )
{
double const xToHiN = expPower( x, logHighestIntN );
double const mAsDouble = floor( n/highestIntN );
int const m = static_cast<int>( mAsDouble );
int const r = static_cast<int>( n - mAsDouble*highestIntN );
return intPower( xToHiN, m )*intPower( x, r );
}
else
{
return intPower( x, static_cast<int>( n ) );
}
}
double positivePower( double const x, double const n )
{
assert( n > 0 );
double const intPart = floor( n );
double const fractionalPart = n - intPart;
if( fractionalPart == 0 )
{
return integralPower( x, intPart );
}
else
{
return integralPower( x, intPart )*fractionalPower( x, fractionalPart );
}
}
double power( double const x, double const n )
{
if( n == 0 )
{
return 1;
}
else if( n < 0 )
{
return 1.0/positivePower( x, -n );
}
else
{
return positivePower( x, n );
}
}
int main()
{
double const x = 2.7; double const n = 3.14;
wcout << setprecision( 16 );
wcout << "Stdlib function result: " << pow( x, n ) << endl;
wcout << "Custom function result: " << power( x, n ) << endl;
}