2010-08-19 11 views
9

Obecnie muszę pracować w środowisku, w którym występuje problem podsłuchu. Czy ktokolwiek może pomyśleć o sposobie tymczasowego obejścia tego błędu i obliczyć^b (oba zmiennoprzecinkowe) bez funkcji lub operatora mocy?Potęgowanie zmiennoprzecinkowe bez funkcji zasilania

+0

"b" zawsze będzie liczbą całkowitą? jeśli tak, po prostu zacznij od 1 i pomnóż przez a, b razy –

+0

a i b są zmiennoprzecinkowe i nie będą to liczby naturalne – ymihere

+0

czy masz dostęp do sqrt()? –

Odpowiedz

22

jeśli sqrt() dostępny:

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); } 

kod testowy:

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; 
} 

wyjścia:

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

+1, miłe! Będę musiał pamiętać tę technikę! –

+2

+1; btw to 'int main()', a nie 'void main' :-) – sasuke

+0

dzięki dużo. właśnie tego właśnie szukałem. Ciekawe: czy możesz dać mi jakieś tło dla tego algorytmu? – ymihere

9

Można użyć tożsamości b = e(b dziennika ), wówczas wszystkie obliczenia odnoszą się do tej samej bazie e = 2,71828 ..

Teraz musisz zaimplementować f (x) = ln (x) i g (x) = e^x. Szybka i mało precyzyjna metoda polegałaby na użyciu tablic przeglądowych dla f (x) i g (x). Może to wystarczy dla twoich celów. Jeśli nie, możesz użyć wyrażenia Taylor series expansions, aby wyrazić ln (x) i e^x w terminach mnożenia i dodawania.

+0

Mam działającą funkcję ln. Jednak w przypadku serii Taylor potrzebuję ponownie mocy. – ymihere

+0

@ymihere: Rozszerzenie serii Taylora zawiera tylko wykładniki całkowite, które można zredukować do mnożenia. –

+0

@ymihere: czy masz dostęp do exp()? jeśli tak, to rozwiązanie jest najlepsze! –

2

podane, że można użyć sqrt ten prosty rekurencyjne działania algorytmu :

Załóżmy, że obliczamy ab. Sposób działania algorytmu polega na szybkiej potęgowaniu na wykładniku, dopóki nie uderzymy w część ułamkową, raz w części ułamkowej, wykonamy zmodyfikowane wyszukiwanie binarne, aż znajdziemy się wystarczająco blisko części ułamkowej.

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; 
    } 
}