2010-08-19 8 views
9

Momentan muss ich in einer Umgebung arbeiten, in der der Power-Operator abgehört wird. Kann jemand an eine Methode denken, die vorübergehend um diesen Fehler herum arbeitet und ein^b (beide Gleitkomma) ohne eine Energiefunktion oder einen Operator berechnet?Fließkomma-Exponentiation ohne Power-Funktion

+0

wird 'b' immer eine ganze Zahl sein? Wenn ja, beginne einfach mit 1 und multipliziere es mit a, b mal –

+0

a und b sind beide Gleitkommazahlen und sind keine natürlichen Zahlen – ymihere

+0

hast du sqrt() verfügbar? –

Antwort

22

wenn Sie sqrt() zur Verfügung:

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

Testcode:

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

Ausgänge:

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

+1, nett! Ich muss mich an diese Technik erinnern! –

+2

+1; btw es ist 'int main()' und nicht 'void main' :-) – sasuke

+0

danke viel. Das ist genau das, wonach ich gesucht habe. Aus Interesse: Kannst du mir einen Hintergrund zu diesem Algorithmus geben? – ymihere

9

können Sie die Identität verwenden einb = e(b log ein), dann werden alle Berechnungen auf die e gleichen Basis bezüglich = 2,71828 .. .

Nun müssen Sie f (x) = ln (x) und g (x) = e^x implementieren. Die schnelle Methode mit niedriger Genauigkeit würde Nachschlagetabellen für f (x) und g (x) verwenden. Vielleicht ist das gut genug für Ihre Zwecke. Wenn nicht, können Sie Taylor series expansions verwenden, um ln (x) und e^x in von Multiplikation und Addition auszudrücken.

+0

Ich habe eine funktionierende ln Funktion. Für die Taylor-Serie brauche ich aber wieder Kräfte. – ymihere

+0

@ymihere: Die Taylor-Reihenentwicklung enthält nur ganzzahlige Exponenten, die auf Multiplikation reduziert werden können. –

+0

@ymihere: hast du exp() verfügbar? Wenn ja, ist diese Lösung am besten! –

2

gegeben, dass Sie sqrt, diese einfache rekursive Algorithmus funktioniert verwenden können :

Angenommen, wir berechnen ab. Die Art und Weise, wie der Algorithmus funktioniert, geschieht durch schnelle Potenzierung des Exponenten, bis wir den Bruchteil, einmal im Bruchteil, eine modifizierte Binärsuche durchführen, bis wir nahe genug am Bruchteil sind.

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