2010-08-19 15 views
9

Actualmente tengo que trabajar en un entorno donde el operador de potencia tiene una falla. ¿Puede alguien pensar en un método que funcione temporalmente alrededor de este error y calcule a^b (ambos puntos flotantes) sin una función de potencia u operador?Exponenciación de punto flotante sin función de potencia

+0

will 'b' always be an integer? si es así, simplemente comience con 1 y multiplíquelo por a, b veces –

+0

a y b son ambos coma flotante y no serán números naturales – ymihere

+0

¿tiene disponible sqrt()? –

Respuesta

22

si ha sqrt() disponibles:

double sqr(double x) { return x * x; } 
// meaning of 'precision': the returned answer should be base^x, where 
//       x is in [power-precision/2,power+precision/2] 
double mypow(double base, double power, double precision) 
{ 
    if (power < 0) return 1/mypow(base, -power, precision); 
    if (power >= 10) return sqr(mypow(base, power/2, precision/2)); 
    if (power >= 1) return base * mypow(base, power-1, precision); 
    if (precision >= 1) return sqrt(base); 
    return sqrt(mypow(base, power*2, precision*2)); 
} 
double mypow(double base, double power) { return mypow(base, power, .000001); } 

código de prueba:

void main() 
{ 
    cout.precision(12); 
    cout << mypow(2.7, 1.23456) << endl; 
    cout << pow (2.7, 1.23456) << endl; 
    cout << mypow(1.001, 1000.7) << endl; 
    cout << pow (1.001, 1000.7) << endl; 
    cout << mypow(.3, -10.7) << endl; 
    cout << pow (.3, -10.7) << endl; 
    cout << mypow(100000, .00001) << endl; 
    cout << pow (100000, .00001) << endl; 
    cout << mypow(100000, .0000001) << endl; 
    cout << pow (100000, .0000001) << endl; 
} 

salidas:

3.40835049344 
3.40835206431 
2.71882549461 
2.71882549383 
393371.348073 
393371.212573 
1.00011529225 
1.00011513588 
1.00000548981 
1.00000115129 
+0

+1, ¡agradable! ¡Tendré que recordar esa técnica! –

+2

+1; por cierto es 'int main()' y no 'void main' :-) – sasuke

+0

muchas gracias. esto es precisamente lo que estaba buscando. Fuera de interés: ¿me puede dar alguna información sobre ese algoritmo? – ymihere

9

Puede utilizar la identidad unb = e(b registro un), a continuación, todos los cálculos son en relación con la misma base e = 2,71828 ..

Ahora debe implementar f (x) = ln (x) yg (x) = e^x. El método rápido y de baja precisión sería usar tablas de búsqueda para f (x) yg (x). Tal vez eso es lo suficientemente bueno para tus propósitos. Si no, puede usar el Taylor series expansions para expresar ln (x) y e^x en los términos de multiplicación y adición.

+0

tengo una función ln en funcionamiento. Sin embargo, para la serie de Taylor necesito poderes otra vez. – ymihere

+0

@ymihere: la expansión de la serie Taylor solo contiene exponentes enteros, que se pueden reducir a multiplicación. –

+0

@ymihere: ¿tiene exp() disponible? si es así, ¡esta solución es la mejor! –

2

considerando que se puede utilizar sqrt, este simple funciona el algoritmo recursivo :

Supongamos que estamos calculando ab. La forma en que funciona el algoritmo es haciendo una exponenciación rápida en el exponente hasta que golpeemos la parte fraccionaria, una vez en la parte fraccionaria, realicemos una búsqueda binaria modificada, hasta que estemos lo suficientemente cerca de la parte fraccionaria.

double EPS = 0.0001; 

double exponentiation(double base, double exp){ 
    if(exp >= 1){ 
    double temp = exponentiation(base, exp/2); 
    return temp * temp; 
    } else{ 
    double low = 0; 
    double high = 1.0; 

    double sqr = sqrt(base); 
    double acc = sqr;  
    double mid = high/2; 

    while(abs(mid - exp) > EPS){ 
     sqr = sqrt(sqr); 

     if (mid <= exp) { 
      low = mid; 
      acc *= sqr; 
     } else{ 
      high = mid; 
      acc *= (1/sqr); 
     } 

     mid = (low + high)/2; 
    } 

    return acc; 
    } 
} 
Cuestiones relacionadas