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


von Cimbom G. (cimbomgs)


Angehängte Dateien:

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

von Jankey (Gast)


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

von Cimbom G. (cimbomgs)


Lesenswert?

Hallo Jankey, danke für die Antwort.

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

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

warum wird int zurückgegeben?

von Gast (Gast)


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)

von Karl H. (kbuchegg)


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
1
#include <math.h>
2
3
int main()
4
{
5
  double x, y;
6
7
  x = 28.3;
8
  y = sqrt( x );
9
}

sollte ohne Probleme und ohne Fehler compilieren.

von Michael G. (linuxgeek) Benutzerseite


Lesenswert?

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

von Cimbom G. (cimbomgs)


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.

>
>
1
> #include <math.h>
2
> 
3
> int main()
4
> {
5
>   double x, y;
6
> 
7
>   x = 28.3;
8
>   y = sqrt( x );
9
> }
10
>
>
> sollte ohne Probleme und ohne Fehler compilieren.

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

von Michael G. (linuxgeek) Benutzerseite


Lesenswert?

Hast Du math.h includiert?
Nachtrag:

Um Quadratwurzel von a zu berechnet, iteriere gemaesz:

von Cimbom G. (cimbomgs)


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.

von Cimbom G. (cimbomgs)


Lesenswert?

Michael G. wrote:
> Hast Du math.h includiert?

math.h ist includiert

von Michael G. (linuxgeek) Benutzerseite


Lesenswert?

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

von Gast (Gast)


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.

von Cimbom G. (cimbomgs)


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

von Michael G. (linuxgeek) Benutzerseite


Lesenswert?

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

von Cimbom G. (cimbomgs)


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?

von Falk B. (falk)


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

von Michael G. (linuxgeek) Benutzerseite


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.

von Karl H. (kbuchegg)


Lesenswert?

1
#include <stdio.h>
2
#include <math.h>
3
4
double MySqrt( double a )
5
{
6
  double Xn = a / 2.0;
7
  double Xnn = 0.0;
8
9
  while( fabs( Xn - Xnn ) > 0.01 ) {
10
    Xnn = Xn;
11
    Xn = Xn / 2.0 + a / ( 2 * Xn );
12
  }
13
14
  return Xn;
15
}
16
17
int main()
18
{
19
  double y = MySqrt( 26.0 );
20
21
  printf( "%lf %lf\n", y, y*y );
22
}

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.

von Cimbom G. (cimbomgs)


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

von Gast (Gast)


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?

von Michael G. (linuxgeek) Benutzerseite


Lesenswert?

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

Gruss,
Michael

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.