Exponent



  • Hallo,
    ich hab eine Schleife und hab eine Gleichung mit einem Exponenten. Nur wie gebe ich den Exponenten im Code ein?
    Ich habe (-1)^(k-1). Und wenn ich das mit diesem Dach mache, funktioniert das nicht. Wie muss ich das denn eingeben??
    MFG



  • Hallo,
    Um zu potenzieren, gibt es die Funktion pow(). Das Dach (^) ist das bitweise xor.

    Gruß Caipi



  • oder mit metatemplates:

    template<int B, int N>
    	struct Pow
    {
    	enum { value = B*Pow<B, N-1>::value };
    };
    
    template<int B>
    	struct Pow<B, 0>
    {
    	enum { value = 1 };
    };
    

    (http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2003/n1471.pdf)



  • Cpt. Tanga schrieb:

    oder mit metatemplates:

    template<int B, int N>
    	struct Pow
    {
    	enum { value = B*Pow<B, N-1>::value };
    };
    
    template<int B>
    	struct Pow<B, 0>
    {
    	enum { value = 1 };
    };
    

    (http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2003/n1471.pdf)

    Aber nur, wenn die Basis und der Exponent bereits zur compile-Zeit feststehen ;). Ist dies jedoch gegeben, ist diese Lösung der Funktion pow() vorzuziehen.

    Gruß Caipi



  • diese lösung ist nicht unbedingt vorzuziehen.das is doch Kinderkacke(ja, ich gebs zu, ich habs auch mal getan 😉 ).

    int pow(int a,int exp){
         if(exp==0){//bei a^0 1 zurückgeben
             return 1;
         }
    
         int ret=1;
         while(exp!=0){
             ret*=a;
             --exp;
         }
         return ret;
    }
    

    1.funktioniert natürlich nur, wenn die argumente ganzzahlig sind. ansonsten ist man eh mit std::pow besser bedient.

    2. wenn die argumente zur compilezeit feststehen wird der compiler das bestimmt auflösen können(und wenn nicht, dann bastelt man solange an der schleife rum, bis der compiler kapiert, dass er sie aufrollen kann)

    3. die compilezeit geht nicht ganz so in den Keller wie bei meta-templates



  • Oder so:

    inline bool isEven(unsigned int z) {
        return z&1==0;
    }
    
    int getModifier(unsigned int k) {
        //returns -1^(k-1)
        if(isEven(k))
            return -1;
        return 1;
    }
    

    😉



  • ... oder so (integer-exponent)

    inline double uPow(double x, unsigned power)
    {
        switch (power)
        {
            case    0   :   if (x != 0.0) return 1;
                                     else return nan;
    
            case    1   :   return x;
    
            case    2   :   return x*x;
    
            case    3   :   return x*x*x;
        };
        double pow2 = uPow(x, power/2);             // gerade - rekursiv halbieren (/2 rundet ab)
        pow2 *= pow2;
        if (power & 1) pow2 *= x;
        return pow2;
    }
    
    inline double iPow(double x, int power)
    {
        if (power < 0) {
            x = 1.0/x;
            power = -power;
        }
        return uPow(x, power);
    }
    


  • peterchen schrieb:

    ... oder so (integer-exponent)
    [snip]

    dann würd ichs aber auch iterativ machen.. zumal dein case 0, case 1 nur beim ersten Aufruf (und nicht bei den rekursiv folgenden Aufrufen) stattfinden kann, da du durch halbieren so schnell erstmal nicht auf 0 oder 1 kommst ohne nicht vorher schon bei 2 oder 3 angekommen zu sein. Also kannste dir bei der halbierungschleife dein case 0, case 1 komplett sparen..



  • man sollte eher case 2, case 3 rausschmeißen (das waren aber die häufigsten Fälle), case 0 ist als spezialfall notwendig, case 1 sinnvoll.

    Ich hab das vor einer ganzen Weile geschrieben, bin aber nie dazu gekommen, mal zu testen, wieviel das eigentlich bringt, wieweit der Compiler das ausrollen kann usw.

    (Wenn switch/case über Sprungtabelle implementiert ist, sind die zusätzliches cases egal, geht höchstens auf den code cache)



  • habs mal getestet:

    double uPow(double x, unsigned power) 
    { 
        switch (power) 
        { 
    		case    3   :   return x*x*x; 
    		case    2   :   return x*x;
    		case    1   :   return x; 
            case    0   :   return 1;   
        }; 
        double pow2 = uPow(x, power/2);             // gerade - rekursiv halbieren (/2 rundet ab) 
        pow2 *= pow2; 
        if (power & 1) pow2 *= x; 
        return pow2; 
    } 
    
    double uPowIt(double x, unsigned power) 
    { 
    	 switch (power) 
    	 { 
            case    0   :   return 1;
    
            case    1   :   return x; 
    
            case    2   :   return x*x; 
    
            case    3   :   return x*x*x; 
         } 
    
    	double tmp = 1.0;
    	while(true) {
    		if(power & 1) {
    			--power;
    			tmp *= x;
    		}
    		power>>=1;
    		x*=x;
    		switch (power) 
    		 { 
                case    2   :   return x*x*tmp; 
                case    3   :   return x*x*x*tmp; 
    		}; 
    	}
    
    }
    
    double uPowIt2(double x, unsigned power) 
    { 
    	 switch (power) 
    	 { 
            case    0   :   return 1;
            case    1   :   return x; 
         } 
    
    	double tmp = 1.0;
    	while(true) {
    		if(power & 1) {
    			--power;
    			tmp *= x;
    		}
    		power>>=1;
    		x*=x;
    		switch (power) 
    		 { 
                case    1   :   return x*tmp; 
    		}; 
    	}
    }
    
    int main() 
    { 
        double erg = 0.0;
    
    	unsigned int max;
    	double basis;
    	cin >> basis;
    	cin >> max;
    
    	float time = (float)clock();
    	for(int j = 0; j < 10; j++)
    		for(unsigned int i = 8; i < max; i+= 1) {
    			erg += uPow(basis,i);
    		}
    	cout << erg  << " " << (float)clock() - time << endl;
    
    	erg = 0.0;
    	time = (float)clock();
    	for(int j = 0; j < 10; j++)
    		for(unsigned int i = 8; i < max; i+= 1) {
    			erg += uPowIt(basis,i);
    		}
    	cout << erg << " " << (float)clock() - time << endl;
    
    	erg = 0.0;
    	time = (float)clock();
    	for(int j = 0; j < 10; j++)
    		for(unsigned int i = 8; i < max; i+= 1) {
    			erg += uPowIt2(basis,i);
    		}
    	cout << erg << " " << (float)clock() - time << endl;
    
    	erg = 0.0;
    	time = (float)clock();
    	for(int j = 0; j < 10; j++)
    		for(unsigned int i = 8; i < max; i+= 1) {
    			erg += pow(basis,(double)i);
    		}
    	cout << erg << " " << (float)clock() - time << endl;
    	system("pause");
    
    }
    

    erg ohne Optimierung:

    0.9
    300000
    43.0467 5985
    43.0467 2078
    43.0467 2187
    43.0467 1797
    Drücken Sie eine beliebige Taste . . .
    

    erg mit Optimierng

    0.9
    300000
    43.0467 1703
    43.0467 1312
    43.0467 1422
    43.0467 1641
    Drücken Sie eine beliebige Taste . . .
    

    hängt aber auch bissel von der basis ab 😣



  • sieht doch nett aus 🙂


Log in to reply