www.mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik wurzel ziehen nicht möglich - Freescale


Autor: Cimbom Gs (cimbomgs)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

ich programmiere einen Freescale Mikrocontroller und brauche für meine 
Rechung eine Wurzel-Funktion. Habe in Library nichts finden können :-(

Im Anhang sieht man die Funktion, die berechnet werden soll.

Für "quadratische Zahlen" (wurzel(25)=5, wurzel(16)=4,...) existiert 
eine Library-Funktion aber damit kann ich nicht anfangen.

Was kann ich machen?
Gibt es andere Möglichkeiten um Wurzel zu ziehen, bzw. Wurzel umgehen?
Oder weiß jemand ob man es vielleicht doch bei Freescale-Mikrocontroller 
realisieren kann?

Danke

ps. obwohl ich math.h includiere, kann ich die sqrt()-Funktion nicht 
benutzen. Der Compiler meckert dass es kein Prototyp existiert

Autor: Jankey (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
__inline int JSqrt(float number)
{
    long i;
    float x2, y;
    const float threehalfs = 1.5f;

    x2 = number * 0.5f;
    y  = number;
    i  = * (long *) &y;      // evil floating point bit level hacking
    i  = 0x5f3759df - (i >> 1);             // what the fugg?
    y  = * (float *) &i;
    y  = y * (threehalfs - (x2  y  y));   // 1st iteration
    //y  = y * ( threehalfs - ( x2  y  y ) );   // 2nd iteration, this 
can be removed

    return (int) (1/y);
}

Autor: Cimbom Gs (cimbomgs)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo Jankey, danke für die Antwort.

Kannst du auch etwas dazu sagen? Was macht die Funktion genau?

was macht das:
i  = * (long *) &y; // evil floating point bit level hacking
i  = 0x5f3759df - (i >> 1); // what the fugg?
y  = * (float *) &i;
y  = y * (threehalfs - (x2  y  y));

warum wird int zurückgegeben?

Autor: Gast (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Slm

also ich kenne mich mit Freescale uC nicht aus und in C habe ich auch 
noch nie programiert aber wenn der math.h exp(x) und ln(x) unterstützt 
kannst du die n-te wurzel aus x so ziehen:

x^1/n=exp(ln(x)/n)

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Gast wrote:
> Slm
>
> also ich kenne mich mit Freescale uC nicht aus und in C habe ich auch
> noch nie programiert aber wenn der math.h exp(x) und ln(x) unterstützt
> kannst du die n-te wurzel aus x so ziehen:
>
> x^1/n=exp(ln(x)/n)


Wobei es eigentlich keinen wirklichen Grund gibt, warum
eine Implementierung zwar keine Wurzel aber ln und exp
unterstützen sollte.

sqrt kann man mit einer Newton Iteration ziemlich einfach
berechnen. Dazu braucht man lediglich Gleitkommaoperationen
Addition, Multiplikation und Division.

> ps. obwohl ich math.h includiere, kann ich die sqrt()-Funktion nicht
> benutzen. Der Compiler meckert dass es kein Prototyp existiert

Kannst du das mal näher ausführen
#include <math.h>

int main()
{
  double x, y;

  x = 28.3;
  y = sqrt( x );
}

sollte ohne Probleme und ohne Fehler compilieren.

Autor: Michael G. (linuxgeek) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Jupps... Wurzeln ziehen kann man auch iterativ, aber Du hast doch eine 
C-Library, oder nicht?

Autor: Cimbom Gs (cimbomgs)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> sqrt kann man mit einer Newton Iteration ziemlich einfach
> berechnen. Dazu braucht man lediglich Gleitkommaoperationen
> Addition, Multiplikation und Division.

oje es ist lange her, dass wir bei der Wurzel-Herleitung in der Schule 
mit Addition, Multiplikation und Division gearbeitet haben. Ich kann 
micht garnicht mehr daran erinnern, wie wir es gamacht haben :-(


>> ps. obwohl ich math.h includiere, kann ich die sqrt()-Funktion nicht
>> benutzen. Der Compiler meckert dass es kein Prototyp existiert
> Kannst du das mal näher ausführen

naja wie gesagt, wenn ich versuche zu debuggen und mein Code compiliere, 
wird mir Linker-Fehler angezeigt. Ich vermute die math.h-Header besitzt 
die Funktion garnicht, daher die Fehlermeldung.

>
>
> #include <math.h>
> 
> int main()
> {
>   double x, y;
> 
>   x = 28.3;
>   y = sqrt( x );
> }
> 
>
> sollte ohne Probleme und ohne Fehler compilieren.

nicht unter CodeWarrior. Nach dem ausführen kommt Fehlermeldung "kein 
Prototyp der Funktion sqrt() vorhanden"

Autor: Michael G. (linuxgeek) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hast Du math.h includiert?
Nachtrag:

Um Quadratwurzel von a zu berechnet, iteriere gemaesz:

Autor: Cimbom Gs (cimbomgs)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Michael G. wrote:
> Jupps... Wurzeln ziehen kann man auch iterativ, aber Du hast doch eine
> C-Library, oder nicht?

ich vermute eine unvollständige C-Library.

Autor: Cimbom Gs (cimbomgs)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Michael G. wrote:
> Hast Du math.h includiert?

math.h ist includiert

Autor: Michael G. (linuxgeek) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ok siehe oben... ;) Du brauchst uebrigens garnicht soviele Schritte, das 
konvergiert recht schnell. Kommt drauf an wieviele sichere Stellen Du 
brauchst.

Autor: Gast (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@   Karl heinz Buchegger (kbuchegg)
>Wobei es eigentlich keinen wirklichen Grund gibt, warum
>eine Implementierung zwar keine Wurzel aber ln und exp
>unterstützen sollte.

wie gesagt habe nch nie in C programmiert. ich denke das QUADRAT WURZEL 
also sqrt(x) in fast jeder Programmiersprache in irgend einer Form 
existiert aber er hat ja nach der N-te Wurzel gefragt und das gibt es 
icht immer als Standart.

> sqrt kann man mit einer Newton Iteration ziemlich einfach
> berechnen. Dazu braucht man lediglich Gleitkommaoperationen
> Addition, Multiplikation und Division.

da hast du recht, wusste aber niht mehr wie das ging.

Autor: Cimbom Gs (cimbomgs)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Michael G. wrote:
> Ok siehe oben... ;) Du brauchst uebrigens garnicht soviele Schritte, das
> konvergiert recht schnell. Kommt drauf an wieviele sichere Stellen Du
> brauchst.

naja 2-3 Nachkommestellen reichen völlig aus

Autor: Michael G. (linuxgeek) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Naja die k-te Wurzel kannste auch berechnen, indem Du das 
Newton-Verfahren mit
 anwendest.

Autor: Cimbom Gs (cimbomgs)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
das n-te Wurzel brauche ich nicht, ich will nur das Quadrat-Wurzel.

o man das ist ja super, dann wäre damit mein Problem geklärt :-D

>Um Quadratwurzel von a zu berechnet, iteriere gemaesz:
>x_{n+1}=\frac{x_n + \frac{a}{x_n}}{2}

nach wievielen Schritten bekommt man 2-3 richtige Nachkommastellen?

Autor: Falk Brunner (falk)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@ Gast (Gast)

>also sqrt(x) in fast jeder Programmiersprache in irgend einer Form
>existiert aber er hat ja nach der N-te Wurzel gefragt und das gibt es
>icht immer als Standart.

Aber AFAIK gibt es eine allgemeine Potenzfunktion pow(x,y) welche

berechnet. Und wer in Mathematik nicht nur Kreide holen war, weiss

sprich pow(x, 1/y);

MfG
Falk

Autor: Michael G. (linuxgeek) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
OK, also fuer 3 Nachkommastellen duerften 4 Iterationen ausreichen, das 
Verfahren konvergiert quadratisch. Ich gebe Dir mal ein Beispiel.

Wenn Du z.B.
 berechnen willst:
 und

Du kannst natuerlich komplett numerisch Rechnen, also nicht mit 
rationalen Zahlen wie in diesem Beispiel. Solltest eventuell noch achten 
dass Du Dir keine Ausloeschungsprobleme einfaengst dabei. Das ergebnis
 verwendet immer
, also das Ergebnis der vorherigen Iteration, siehe oben.

Falls Du eine allgemeine Potenzfunktion hast geht es natuerlich auch so. 
Dann liegt es aber nahe dass Du die Wurzelfunktion auch zur Verfuegung 
hast.

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
#include <stdio.h>
#include <math.h>

double MySqrt( double a )
{
  double Xn = a / 2.0;
  double Xnn = 0.0;

  while( fabs( Xn - Xnn ) > 0.01 ) {
    Xnn = Xn;
    Xn = Xn / 2.0 + a / ( 2 * Xn );
  }

  return Xn;
}

int main()
{
  double y = MySqrt( 26.0 );

  printf( "%lf %lf\n", y, y*y );
}

Wenn du den Aufwand mit der While Schleife nicht brauchst,
sollte es (je nach Zahlenbereich von a) ausreichen einfach

double MySqrt( double a )
{
  double Xn = a / 2.0;

  Xn = Xn / 2.0 + a / ( 2 * Xn );
  Xn = Xn / 2.0 + a / ( 2 * Xn );

  return Xn;
}

Wenn das nicht reicht, dann iterierst du ganz einfach noch mal :-)

  Xn = Xn / 2.0 + a / ( 2 * Xn );
  Xn = Xn / 2.0 + a / ( 2 * Xn );
  Xn = Xn / 2.0 + a / ( 2 * Xn );

Und wenn das dann immer noch nicht reicht, dann halt noch ein 4.tes
mal:

  Xn = Xn / 2.0 + a / ( 2 * Xn );
  Xn = Xn / 2.0 + a / ( 2 * Xn );
  Xn = Xn / 2.0 + a / ( 2 * Xn );
  Xn = Xn / 2.0 + a / ( 2 * Xn );

Du kannst beliebig oft iterieren, jedesmal wird das Ergebnis
genauer.

Autor: Cimbom Gs (cimbomgs)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Waow das ist klasse, super vielen Dank.

Habt vielen dank für eure Hilfe.

Ps. jetzt kann ich mich wieder an die Schulzeit erinnern :-). Genau so 
haben wir es die Wurzel-Funktion hergeleitet und für das n-te Wurzel gab 
es mehrere Möglichkeiten. Einer von den war das Newton-Verfahren

Nochmals Dankeschön

Autor: Gast (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@  Falk Brunner (falk)
>Aber AFAIK gibt es eine allgemeine Potenzfunktion pow(x,y) welche

siehe oben:
>also ich kenne mich mit Freescale uC nicht aus und in C habe ich auch
noch nie programiert

noch mal siehe oben:
>wie gesagt habe nch nie in C programmiert.

aus beiden aussagen kann man herleiten das ich nicht wissen kann ob 
einer power in C implementiert ist.

>Und wer in Mathematik nicht nur Kreide holen war,

siehe oben:
>x^1/n=exp(ln(x)/n)
ist das nicht das selbe pow(x,1/n)=x^1/n?

Autor: Michael G. (linuxgeek) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Bidde bidde... das Wurzelziehen auf die Art nennt sich uebrigens 
Heronverfahren, ist aber nur ein Spezialfall des Newton-Verfahrens.

Gruss,
Michael

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.