für Interessierte:
Hier meine selbst geschriebenen und auch selsbt ausgedachten (außer sinus) Festpunktfunktionen.
Alle Funktionen arbeiten im Gradmaß!!! mit 7 Festkommabits das erspart einem die umrechnung mit PI
Code:
int16_t arccos(long number); //Eingabe 14 Festkommabits Ausgabe 7 Festkommabits
int16_t arctan(long number); //Eingabe 10 Festkommabits Ausgabe 7 Festkommabits
int16_t arctan2(int16_t y,int16_t x); //Eingaben proportional Ausgabe 7 Festkommabits
int16_t cosinus(long x); //Eingabe 7 Festkommabits Ausgabe 14 Festkommabits
inline int8_t signf(float number); //liefert 1 für positive und -1 für negtive Zahlen des tüps float
inline int8_t signl(long number); //des typs long (32-Bit)
inline int8_t signi(int16_t number); //des typs int16_t
int16_t sinus(long x); //Eingabe 7 Festkommabits Ausgabe 14 Festkommabits
uint16_t sqroot(unsigned long number); //Eingabe positive ganzzahl
//**************************************************// 100-1200 Takte*
uint16_t sqroot(unsigned long number) // O(n)=log_2(n) Max Abweichung meistens 0 oder 1, selten 2 bzw. 0.1% für große zahlen
{
if(number==0) return 0; //triviale Fälle abfangen
if(number==1) return 1;
unsigned long r2;
uint16_t root=0,delta;
if(number>=64536) //falls die Zahl größer als eine 16 Bit Zahl ist
delta=32768; //maximal mögliche Wurzel versuchen (2^15+2^14+2^13...=65535)
else
delta=(number>>1); //sonst beginn bei der Zahl selbst druch 2
while (delta) //liefert binnen 15 Iterationen eine Lösung
{
r2=(unsigned long)root*root;
if(r2<number)
root+=delta;
else
root-=delta;
delta=(delta>>1);
}
return root;
}
//**************************************************//
//**************************************************// 762 Takte*
const long W=23040UL; //Winkel eines Halbkreises Skalierung 128 = 7 Festkommabits
const long W2=46080UL; //Winkel eines Vollkreises
const uint16_t Wd2=11520; //Winkel eines Viertelkreises häufige verwendung spart Rechenzeit
int16_t sinus(long x) //
{
if(x>W2) x%=W2; //Skalierung auf den bereich [0;W2] (Sinuswelle)
if(x>W) x=-x+W; //x wird auf das Intervall [-W;W] normiert (aufgrund der Achsensymmetrie um x=0)
if(x<-W) x=-x-W;
//Parabel
const long B = 182; //2^-13 //(4/W); //linearer Formfaktor der Parabel
const long C = -259;//2^-21 //(-4/(W*W)); //quadratischer Formfaktor der Parabel
long y=((B*x)>>6)+((((C*x)>>11)*x*signl(x))>>10); //2^-14 //Funktionswert der einfachen Parabel
//Parabel Korrektur
const long Q = 99; //2^-7 //0.775; //Linearfaktor der einfachen parabel
const long P = 29; //2^-7 //0.225; //Linearfaktor der quadrierten korektur Parabel
y=((Q*y)>>7)+((((P*y)>>7)*y*signl(y))>>14); //2^-14 //Endergebnis nach gewichteter Summenbildung
return y;
}
//**************************************************//
//**************************************************// 768 Takte*
int16_t cosinus(long x) //
{ //
return sinus((x+Wd2));
}
//**************************************************//
//**************************************************// 1800 Takte*
int16_t arccos(long number) //
{ //
if (number==0) return Wd2; // 0 Abfangen
else if (number>=16384) return 0; // Werte größer 1 und kleiner -1 abfangen
else if (-number>=16384) return W;
if (signl(number)==1) // number>=0
return ((((long)sqroot(16384-number)*151511)>>11)+(((long)(16384-number)*4101)>>15)); //Faktoren 2^-11 und 2^-8 Ergebnis 2^-7
else
return (W-((((long)sqroot(16384+number)*151511)>>11)+(((long)(16384+number)*4101)>>15)));
}
//**************************************************//
//**************************************************// 974 Takte*
int16_t arctan(long number) //
{ //
int8_t v;
unsigned long x;
if (number==0) return 0;
if (number>0) {x= number;v=1;} // Betrag und Vorzeichen von number
else {x=-number;v=-1;}
if (x> 8388608UL) return (v* Wd2); //für |x|>2^13 gilt +-90°
if (x<1024) //für x<1 gilt allg.: x/(1+0.28x)
return v*(((209539UL*x)>>3)/(((x*x)>>10)+3657)); //zähler/nenner= 2^-17/2^-10=2^-7
else if(x<60000UL) // sonst gilt allg.: PI/2-x/(x²+0.28)
return v*(Wd2-((58671UL*(x>>3))/(((x*x)>>10)+287))); //zähler/nenner= 2^-17/2^-10=2^-7
else
{
x=(x>>5); //anpassung zum Schutz vor Überläufen
return v*(Wd2-(((58671UL*x)>>8)/(((x*x)+287)>>10))); //zähler/nenner= 2^-7/2^0=2^-7
}
}
//**************************************************//
//**************************************************// 1729 Takte*
int16_t arctan2(int16_t y,int16_t x) //
{ //
if(x==0) //Vorzeichenorientierte Fallunterscheidung
{
if (y==0) return 0;
else return signi(y)*Wd2;
}
if(x>0) return arctan(((long)y<<10)/x);
else return arctan(((long)y<<10)/x)+signi(y)*W;
}
//**************************************************//
//**************************************************// 5 Takte*
inline int8_t signf(float number)
{
if (signbit(number))
return -1;
else
return 1;
}
inline int8_t signi(int16_t number)
{
if(number&(1<<15))
return -1;
else
return 1;
}
inline int8_t signl(long number)
{
if(number&(1<<31))
return -1;
else
return 1;
}
//**************************************************//
Lesezeichen