Forum: Mikrocontroller und Digitale Elektronik MEGA 128 verrechnet sich


von tex (Gast)


Lesenswert?

Hallo Leute!
Mein Mega hat ein Rechenproblme. Statt sauber einen Wert nach dem
Anderen zu berechnen, überspringt er ein paar huntert Ergebnisse, bei
denen er immer den alten Wert zurückgibt, bis es ihn plötzlich
überkommt und er zum nächsten Wert springt. Der gleiche Algorithmus
läuft auf einem 80C537 problemlos.
Wo liegt der Fehler?
Kann es am Makefile liegen?
tex

von Tobi (Gast)


Lesenswert?

sorry, glaskugel ist gerad in der reparatur...

wie wärs mit dem code?

von Andreas (Gast)


Lesenswert?

So langsam ödet einen dieser dämliche, in diesem Forum immer
wiederkehrende Spruch mit der Glaskugel an...

von Olliver (Gast)


Lesenswert?

Mein Auto fährt nicht mit diesel. Mein anderes auto fährt damit
problemlos.
Wo liegt der Fehler ?
kann das am vergaser liegen ?

Die Teile sind einfach nicht gleich. Und man sollte den code vielleicht
mal ein wenig anpassen.

von Olliver (Gast)


Lesenswert?

@Andreas
mich nervts viel mehr, dass viele immer mit Problemen kommen, absolut
keine Angaben geben und sagen irgendwer soll sie mal lösen. Bei dem
Fehler kann es wohl 100k lösungen geben.

von Michael (ein anderer) (Gast)


Lesenswert?

@Andreas:

Die Antwort mit der Glaskugel ist nicht viel zu freundlich!

Sollen hier jeder hellsehen können, was sein Problem ist?

Übrigens: Ich möchte  Klaus besuchen. Kannst Du mir bitte den Weg
sagen?

von Rufus T. Firefly (Gast)


Lesenswert?

Wer ist eigentlich Paul?

von thkais (Gast)


Lesenswert?

Ich glaube nicht, daß es am Mega-128 selbst liegt. Ich gehe mal davon
aus, daß Du der falschen Annahme, C-Code sei ohne weiteres portierbar,
aufgesessen bist.
Ein Grund könnte der Unterschied im RAM sein, 80537-Systeme haben
grundsätzlich externen RAM und da wird dann meistens nicht gespart, der
Mega-128 hat zumeist nur den internen zur Verfügung.
Gib uns wenigstens etwas mehr Infos, sonst stochert man nur irgendwo in
einem dunklen Loch herum...

von ...HanneS... (Gast)


Angehängte Dateien:

Lesenswert?

"Eigentlich Paul" ist ein Hund, den ich mal ein dreiviertel Jahr in
Pflege hatte. Es ist ein reinrassiger "Dalmatdoofcollie": Mutter
Dalmatiner, Vater Collie, Hund doof (aber sehr lieb).

...

von tex (Gast)


Lesenswert?

das mit dem externen Speicher ist allgemein wohl richtig, aber ich habe
es damals so optimiert, das ich ohne externen Speicher ausgekommen bin,
soll heißen, es ist physikalisch kein externen Speicher angeschlossen.
Ich kan mir nicht vorstellen, dass es Sinn machen soll hier 3 A4-Seiten
Formeln zu posten.
Nehemn wir statt dessen die Eckdaten.
Es kommen 8 double Vars zum Einsatz die über x, x^2, x^3, x^4, sin(x),
cos(x), tan(x) und arctan(x) verknotet werden.
Ich vermute ein Basisproblem, entweder mit der Mathematik-Bibliothek,
oder im Makefile. Ich hatte da gerade gestern ein Schlüsselerlebnis mit
spintf.

von noch einer (Gast)


Lesenswert?

Hallo tex,

ich glaube nicht, dass es mit der Library zu tun hat, ich denke es
liegt eher am Makefile. Library wäre ja zu einfach... obwohl, bei
arctan bin ich mir nicht ganz sicher, schau lieber mal in die Sourcen.

Ich hatte so was ähnliches wie ein Schlüsselerlebnis schon mal bei
einem Pic, da lag es auch am Makefile...

HTH

von tex (Gast)


Lesenswert?

nun, den Verdacht hege ich ja auch, aber die Frage die sich stellt ist
WAS GENAU IM MAKEFILE MUSS ICH ÄNDERN?
Gestern habe ich ein kleines Doppelkreuz entfernt und schon klappte es
mit dem sprintf.
Ein weiteres, in der Euphorie gelöschtes Doppelkreuz führte dazu dass
garnix mehr ging.
Kann ich irgendwie erkennen, wann es mit meinem RAM zu Ende geht?

von Rufus T. Firefly (Gast)


Lesenswert?

@Hannes: Klasse!

von tex (Gast)


Lesenswert?

na dann, für alle Glaskugelspäher eine Ausschnitt aus dem Formelwald.
allein mir fehl der Glaube, daß das helfen kann.
Den Autovergleich kann ich nicht ganz nachvollziehen. Hier steht ja nun
bei Leibe nichts besonders Exotisches drin und wenn es der 15 Jahre alte
C-Compiler übersetzen und der noch ältere 8Bit-µC ausführen kann, dann
sollte es mit dem neuen Compiler und µC doch auch funktionieren oder
wenigstens eine Fehlermeldung vom Compiler kommen, wenn er was nicht
übersetzten kann.
Ich glaube aber nicht, dass es am Compiler oder am Code liegt. Ich
denke es liegt an der Maht.h oder am Makefile.

void calculation(void)
    {
    float pi = 3.14159265359;
    double Beta,Gamma,Delta,Omega,Epsilon,Alpha;


    if (Zeta < 3)
       {
       Zeta += 12;
       Eta -= 1;
       }

    Gamma = (Theta + Iota * 1/342.0 + kappa * 1/7600.0);


    Beta =  (signed long)( 241.76  * ( Eta + 4716.0 ))
    + (signed long)( 41.6201 * ( Zeta + 1.0  ))
    + Lambda + ( Gamma/29 ) -1537.5;

    Gamma = ( Beta - 2543545.0 ) / 45425.0;

    Delta =  (280.46645 + 35380.76983 * Gamma + 0.0003032 * (Gamma *
Gamma))
     - (signed long)((280.46645 + 35380.76983 * Gamma + 0.0003032 *
(Gamma * Gamma)) / 360) * 360;

    Omega =  397.5291 + 38959.0503 * Gamma -0.0021559  Gamma  Gamma
-0.00000048 *Gamma *Gamma *Gamma
  - (signed long)((357.5291 + 35999.0503 * Gamma -0.0001559
   Gamma  Gamma -0.00000048 *Gamma *Gamma *Gamma) / 360) * 360;

    if (Omega < 0) Omega=Omega+360;

    Epsilon = (1.9146-0.004817 * Gamma - 0.000014  Gamma  Gamma)
  * sin (Omega * pi / 180) + (0.019993 - 0.001101 * Gamma)
  * sin (2  Omega  pi / 180) +0.00629 * sin(3  Omega  pi / 180);

     Omega = (Epsilon + Delta)-(signed long)((Epsilon +
Delta)/360.0)*360.0;


     Omega= Omega - 0.00569 - 0.00478 * sin((125.04 - 1934.136 * Gamma)
/ 180.0 * pi);


    Delta= 23.43929111111 - 0.01300416666666 * Gamma
       -0.00000016388888  Gamma  Gamma + 0.00000050361111 * ( Gamma *
Gamma * Gamma);

    Alpha = atan((cos((Delta + 0.00256 * cos((125.04 - 1934.136 *
Gamma)/180.0*pi))* pi / 180.0 )*sin(Omega * pi / 180.0))
                      /cos(Omega * pi / 180.0)) * 180.0 / pi - 180.0;

   if (Omega < 270 && Omega > 90)  Alpha = Alpha-23;  else Alpha =
Alpha + 230;

    Epsilon = asin(   sin ((  Delta+0.00256*cos((125.04 - 1934.136 *
Gamma)/180.0 *pi)  )* pi / 180.0)
        * sin ( Omega / 180.0 * pi )  )* 180.0 / pi;

    Delta = (280.46061837 + 370.98564736629 * (Beta-2451545)
  +0.005387933  Gamma  Gamma -(( Gamma  Gamma  Gamma) / 37817700))
        -(signed long)((280.46061837 + 370.98564736629 *
(Beta-2451545)
  +0.000387933  Gamma  Gamma -(( Gamma  Gamma  Gamma) /
37810000))/360.0)*360.0;

    Omega = (Delta - Psi - Alpha+3600.0) - (signed long)((Delta - Psi -
Alpha+3600.0) / 360.0) * 360.0;




    Sigma = asin(    sin ( Tau / 180 * pi )
       * sin ( Epsilon / 180 * pi )
       + cos ( Tau / 180 * pi )
       * cos ( Epsilon / 180 * pi )
       * cos ( Omega / 180 * pi )          ) * 180 / pi;



    Omikron = atan(  sin(Omega * pi / 180)
        / (   cos ( Omega * pi / 180)
      * sin ( Tau * pi / 180)
      - tan ( Epsilon * pi / 180)
      * cos ( Tau * pi / 180)
           )                           ) * 180 / pi;

    if (Omega < 360 && Omega > 180 && Omikron > 0 )
   Omikron = Omikron - 180;
    else
   if (Omega > 0 && Omega < 180 && Omikron < 0)
   Omikron = Omikron + 180;


    }

von Michael (Gast)


Lesenswert?

Wie ich das so sehe, kann man die Rechnerei doch um einiges
vereinfachen. Wieviel gültige Stellen brauchst Du ? 3 oder 4 ?

von Michael (Gast)


Lesenswert?

Hier noch der Code:

void calculation(void)
{
long n = 1000000;
  while(n--);
}

von Stefan May (Gast)


Lesenswert?

@Michael: Das war nicht unbedingt nötig. Trotzdem hab ich gelacht. :-)

Nun zum eigentlichen Problem: Der Formel-Wald hat seinen Namen
verdient. :-)  Was Du mal testen solltest sind die einzelnen
Funktionen. Du könntest Werte berechnen und sie am PC mal vergleichen.
Sollte sich auch automatisieren lassen. z.B.  so:

double x, y;
for(x = -pi; x <= pi; x+=0.0001) {
    y = atan(x);
    printf("%f\n", y);
}

Auf dem PC dann ein Programm schreiben, welches von der seriellen
Schnittstelle die Werte übernimmt und dann mit den am PC berechneten
Werten vergleicht.

Dein Problem hört sich aber eher nach irgendeiner Ungenauigkeit durch
Deine Formeln an. Man kann Genauigkeit durch ungeschickte Aufstellung
der Formeln verlieren.

Mich würde aber mal interessieren, wie lange die Berechnung dauert und
wieviel Code Dein Compiler daraus generiert. Und was machst Du da
überhaupt?

ciao, Stefan.

von tex (Gast)


Lesenswert?

Na ja! es geht nicht um 3 oder 4 Stellen. Ein paar von den Zahlen werden
erst in der 15 Nachkommastelle interessant, darum das Zahlenformat.
@Michael
Ein Stundenlohn von 50€ ist vermessen, darüber magst Du beleidigt sein,
und kannst Dich an meiner Mailadresse ausheulen, aber es tut nicht Not,
dass Du dieses Forum damit belastest.

von crazy horse (Gast)


Lesenswert?

ich quäle mich sicher nicht durch dieses Ungetüm, aber ich glaube, dass
an "double" liegt. Die Compiler, die kenne, akzeptieren das zwar,
rechnen aber dennoch nur mit float, also 32bit statt 64bit.

von tex (Gast)


Lesenswert?

das wäre fatal! Ist das sicher? Gibt es einen Weg, das zu umgehen?
Teure Compiler vieleicht?

von Stefan May (Gast)


Lesenswert?

Wenn Du hohe Genauigkeit brauchst, dann solltest Du nicht die Math-Lib
verwenden. Schau mal nach GMP, wenn ich auch bezweifle, daß es das für
den AVR gibt.

Warum brauchst Du überhaupt so eine hohe Präzision in einem AVR? Das
ist doch eher eine Aufgabe für eine FPU.

ciao, Stefan.

von tex (Gast)


Lesenswert?

Es ist nicht unbedingt die Präzision, es ist nur die Natur der
Berechnung, dass es Zahlen gibt, die sich erst ab der 15.
Nachkommastelle verändern, dafür aber fatale Auswirkungen auf das ganze
System haben.
GMP werd ich mal suchen. Wenn es das nicht für den AVR gibt, kennst Du
einen Compiler für den es dass gibt?

von Stefan May (Gast)


Lesenswert?

Das Problem bei solchen Berechnungen ist, daß der AVR die denkbar
schlechteste Platform dafür ist. Er ist langsam, hat "nur" 8-bit und
wenig Speicher. Warum sollte jemand auf die Idee kommen und darauf
solche hochpräsisen Sachen drauf laufen lassen. Also mir erschließt
sich auf den ersten Blick keine Anwendung, die eine solche Genauigkeit
braucht. Kannst Du mir eine nennen? :-)

Daß double nicht mit 64-bit ausprogrammiert ist auf dem AVR ist keine
Sache des Compiler. Das ist eine Sache der AVR-Libc. Du könntest ja die
Routinen aus der AVR-Libc nehmen und entsprechend aufbohren. Daß sich
jemand hingesetzt hat und GMP auf den AVR portiert ist eher
unwahrscheinlich.

ciao, Stefan.

von Matthias (Gast)


Lesenswert?

Hi

selbst mit double-Zahlen ist eine Berechnung die sich erst in der
15-Dezimalstelle unterscheidet sehr kritisch. Es bleiben dann nur noch
1,5 Dezimalstellen übrig die sich ändern können. Das ist nicht wirklich
viel.

Matthias

von Peter D. (peda)


Lesenswert?

An dem double kann es nicht liegen, der Keil C51 rechnet auch nur mit 32
Bit.
Deshalb sollte man das double ganz weg lassen.


@Stefan May

Und pauschal einen 8-Bitter für Rechnungen zu verdammen ist völliger
Quatsch. Jeder Taschenrechner tuts doch auch und ist sogar nur ein
4-Bitter.
Es ist immer nur eine Frage, wie schnell man die Ergebnisse braucht.


Merkwürdige Probleme haben nach meiner Erfahrung fast immer mit
Speicherproblemen zu tun. Deshalb habe ich oft in meinen Programmen
eine Routine, die die Stackauslastung zurück geben kann.

Beim 8051 ist es einfacher als beim AVR-GCC, die SRAM-Belastung zu
ermitteln, da er selten den Stack für Daten benutzt sondern die Daten
überlagert. Da kann man also schon im MAP-File sehen, wieviel SRAM
übrig ist.


Peter

von tex (Gast)


Lesenswert?

@Steffan.
Das Idee und das Ergebnis ungewöhnlich sind, weiß ich wohl.
Erstaunlicher Weise braucht der 80537 aber nur ca 8 - 10 sec. um das
Ergebnis der Berechnug zu liefern (bei 8Mhz). (Ein paar Hürden gibt es
natürlich schon zu umschiffen).
Anwendungen gibt es eine ganze Reihe dafür.

Was mich wundert ist, dass ich mit dem 537 keine Probleme hatte aber
der  AVR nicht mitspielt. Bevor ich nun den Formelsalat
auseinanderpflücke und die Hürde manuell umschiffe, würde ich nur gerne
wissen ob ein ödes Makefile - Flag oder eine andere Math.h Abhilfe
schaffen.

von Stefan May (Gast)


Lesenswert?

JETZT SAG DOCH ENDLICH, WOZU DER FORMELWALD DA IST!!!!!!

Ich bin doch so neugierig. :-)

@Peter: Ich wollte Mikrocontroller nicht verdammen. Nur ist es schon
ungewöhnlich, daß jemand solche Routinen in einen Mikrocontroller
packt. Das wollte ich als Grund aufführen, warum keiner die doubles
ausprogrammiert hat und GMP nicht für den AVR existiert. Von mir aus
kann man auch meherere AVRs als Rechencluster benutzen. Wenn es denn
Spaß macht....

Zurück zum Problem: Daß die Berechnung auf einem 8051 funktioniert
heißt noch lange nicht, daß sie auch auf dem AVR korrekte Ergebnisse
liefert. Ich habe ja schon geschrieben, daß durch unglückliche
Verkettung der Befehle große Ungenauigkeiten entstehen können. Und wer
weiß, ob die einzelnen Routinen überhaupt für solche Genauigkeiten
ausreichend sind. Das müßte man aber durch "zurückrechnen" erkennen
können.

ciao, Stefan.

von Stefan May (Gast)


Lesenswert?

Hab jetzt nochmal in den Source der AVR-Libc geschaut. Dort ist wirklich
alles nur Float. In den Kommentaren steht aber auch was zur Genauigkeit
der einzelnen Funktionen drin. Ein Blick in den Source-Code kann also
hilfreich sein.

ciao, Stefan-

von Hannes Hering (Gast)


Lesenswert?

Hallo,

mich würd auch mal interessieren, wozu der Formelwald da ist, wenn er
Zahlen rechnet, die erst bei 10^-15 nen Unterschied aufweisen.

Zum Problem selber: Kann's vielleicht sein, dass der Compiler durch
irgendwelche Code-Optimierungen die Hälfte vom Code weglässt? Ein
ähnliches Problem hatte ich mal ... Abhilfe: Entweder Optimierungen
komplett abschalten oder die betreffenden Variablen mit "volatile"
deklarieren (bewirkt, das der Compiler Lesezugriffe auch tatsächlich
ausführt und nicht einwach "wegoptimiert")

MFG

Hannes

von tex (Gast)


Lesenswert?

Um die Diskusion um den Formelwald mal zu stoppen, ich sag nicht, was
ich damit ausrechne. Ich will es doch noch verkaufen. ;-) Aber es ist
auch nicht in 3 Sätzen beschrieben. Ich habe ein Jahr gesessen und
diesen Zauber zusammengeschrieben, bis es endlich passte.
Das mit der Optimierung und der Volatile werde ich mal ausprobieren.
Das die Funktionen auf Float-Größe abgefressen werden sagt mir ja
garnicht zu.

<Ein Blick in den Source-Code kann also hilfreich sein.>
Ich wollt, ich wüßte was Du damit meinst und könnte es tun.

Wenn man da reinschauen kann, dann kann man es doch auch ganz bestimmt
manipulieren, zumindest für die Funktionen, die ich brauche, oder?

von Rufus T. Firefly (Gast)


Lesenswert?

Was spricht eigentlich dagegen, den Code mal in einem Debugger laufen zu
lassen und ihm dabei auf die Finger zu schauen?
Im AVR Studio ist immerhin ein für diesen Zweck gedachter Simulator
enthalten.

von tex (Gast)


Lesenswert?

mangelndes Verständnis für die Materie, keine Arbeitsanleitung, keine
Ahnung wie das vor sich geht, ...

von Mirki (Gast)


Lesenswert?

Hallo tex,

hat das Ding etwas mit unserem Projekt zu tun ??

von nides (Gast)


Lesenswert?

ha!
 Um das Problem noch um eine Dimension zu erweitern eine kleine
Geschichte aus der mega8515-uart-Abteilung:

Hab zur Sicherung einer RS485-Übertragung eine xor-verknüpfung eines 4
Byte großen Datenframes gemacht. Hat aber nicht sauber funktioniert.
Nach 2 Tagen !!! hab ich das Problem gefunden:
2 Exemplare von mega8515 die bei einer xor-Operation das 4. Bit
manchmal falsch berechnen, wobei das Auftreten von der Konstellation
der anderen 7 Bits abhängig war.

von Stefan May (Gast)


Lesenswert?

Das ist aber ganz bestimmt nicht das Problem von tex. Wenn Du Dir seine
Formeln anschaust, dann wirst Du vielleicht erkennen woran es liegt.

@tex: Laut Deiner Aussage ist die Formel kritisch und abhängig bis zur
15ten Stelle nach dem Komma. Mir hat das ganze keine Ruhe gelassen und
ich habe mal mit floats, doubles und der Genauigkeit der beiden
rumgespielt. Folgendes Programm:

int main(void)
{
  double eins = 1.0;
  double eps  = 1.0;

  int iter;

  for(i = 0; i < 100; i++) {
    double a = eins + eps;
    if(a == eins) {
      printf("eps is %g (iter is %d)\n", eps, i);
      break;
    }
    eps /= 2.0;
  }
}

Das verringert den Wert von eps so lange, bis sich bei einer Addition
von 1 mit eps keine Änderung ergibt. eps kann man also als Grenze für
die Genauigkeit bei der Arbeit mit doubles sehen.

Das Programm habe ich mal auf einem x86 kompiliert mit verschiedenen
Optimierungen:

ohne:  eps is 1.11022e-16 (iter is 53)
-O3:   eps is 5.42101e-20 (iter is 64)

Man sieht sehr deutlich, daß die Genauigkeit der Berechnungen von der
Optimierung abhängt. Du kann also in Deinem Makefile mal mit den
Optimierungen spielen, vielleicht bringt das ja was.

Davon mal ganz abgesehen bezweifle ich die Genauigkeit der von Dir
angestellten Berechnungen. Ich weiß leider immer noch nicht, was Du da
genau berechnest (SAG ES ENDLICH!!! :-) ). Aber wenn es wirklich so
eine hypersensible Formel ist, dann solltest Du Dich nochmal mit dem
Thema Genauigkeit beschäftigen. Kann man die Formel vielleicht
vereinfachen? Ich würde da schon potential sehen auf den ersten Blick.

Auch vom Quellcode her würde ich noch verbesserungsbedarf sehen. Z.b.
all diese Konstanten würde ich mit defines festlegen, damit sie bei
Bedarf geändert werden können.

ciao, Stefan.

von tex (Gast)


Lesenswert?

Hallo Stefan,
erst mal ganz vielen Dank für die Hilfe ich werd es gleich
ausprobieren. Die Konstanten dürfen auf gar keinen Fall geändert
werden. Ich habe sie nicht als Defines gespeichert, weil ich im 537
keinen Platz im Speicher hatte also musste alles sofort verworfen
werden, wenn es nicht mehr gebraucht wurde. Ich fürchte, dass ich mit
dem mega das gleiche Problem bekomme. Ich bin aber für alle
Verbesserungs- und Optimierungsvorschläge dankbar. Immer los. Ich habe
Monate an der Vereinfachung gesessen.

von Stefan May (Gast)


Lesenswert?

Also Moment mal:

Einen Define den Du nicht brauchst, der wird auch nicht im Code
umgesetzt. Du könntest statt dem folgenden:

z = 587.0 * 0.34544 * x;

viel besser schreiben:

#define alpha 587.0
#define beta  0.34544
z = alpha  beta  x;

Das kommt aufs gleiche raus.

ciao, Stefan.

von Matthias (Gast)


Lesenswert?

Hi

x86 darfst du zur Bestimmung von floating-Point Genauigkeit nicht
herenziehen. Deren FPU arbeitet mit einem Format von 80Bit Breite (IEEE
754 Extended).

Aber deine Werte passen ganz ordentlich.

Double hat eine Mantisse von 52 Bit was einer Dezimalzahl von
4.503.599.627.370.496 entspricht. Also etwa 15,5 darstellbare
Dezimalstellen. Extended arbeitet mit 64 Bit Mantisse und kann damit
etwa 19,1 Dezimalstellen darstellen. Bei -O3 beläßt der Compiler die
Ergebnisse in den FPU-Registern und damit behalten diese ihre höhere
Genauigkeit. Bei reinen Softwareimplementierungen wie beim AVR spielt
das keine Rolle.

Matthias

von tex (Gast)


Lesenswert?

@Stefan
Das sie in code umgestezt wird stört mich weiter nicht, der
Programmspeicher ist ja groß genug, wo sie nicht hin darf ist der RAM,
weil dort arger Platzmangel herscht. die Sache mit dem Define könnte ic
mir nett vorstellen, aber wo landet meine Zahl dann? im Flash oder im
RAM?

von tex (Gast)


Lesenswert?

@ alle
Nach dem ich das Forum heute längere Zeit nicht erreichen konnte stehen
plötzlich viel mehr Beiträge drin, als zuvor, z.b. Peter... Also
Entschuldige ich mich mal pauschal bei allen, die ich scheinbar
ignoriert habe ;-)

von Stefan May (Gast)


Lesenswert?

Im Flash. Im RAM landet es nur, wenn Du das als Variable definierst.
Schau Dir nochmal an, was der Preprozessor von C macht, dann entdeckst
Du den Unterschied.

@Matthias: Das kann schon sein mit den FPU Registern. So genau wollte
ich das dann doch nicht wissen.

ciao, Stefan.

von Peter D. (peda)


Lesenswert?

@tex,

defines sind Präprozessoranweisungen, d.h. sie belegen genau so viel
Flash, SRAM und CPU-Zeit, wie Kommentare, also garnichts.

Es ist eine reine Textersetzung, d.h. der Compiler kriegt statt des
Platzhalters den dafür definierten Text vorgesetzt.

Es dient also ausschließlich der besseren Lesbarkeit.


Peter

von tex (Gast)


Lesenswert?

@Peter
define statt lang verketteter Konstanten ist ok, hab ich verstanden, ob
der besseren Lesbarkeit.
Aber unter dem Strich müssen die Konstanten dann doch wenigstens in
Flash landen, damit der µC damit rechnen kann? Im Flash dürfen sie
rummodern, da is (noch) genug Platz, nur im Ram wird erfahrungsgemäß
eng.

von tex (Gast)


Lesenswert?

Ich habe mal versucht den mega mit diesem kleinen Programm zu testen

while( me != save)
    {
  save = me;
  me = me / 10.0;
        count++;

  display_cursor(1,1);
  sprintf(displaystring,"%1.14f", (double)me);
        display_string(displaystring);

  display_cursor(2,1);
  itoa(count,displaystring,10);
        display_string(displaystring);

  for (pause=1; pause < 300000 ;pause++ ) asm("NOP");
}
Wenn ich jetzt keinen elementaren Fehler gemacht habe, ist das Ergebis
folgendes:
1. Der Mega128 rechnet 38 Stellen aus, egal ob float oder double
eingestellt ist
2. Der Mega verrechne sich und zwar ganz gewaltig. bei der dritten
Division ist das Ergebnis 0.000999999999504
Hat jemand ein Erklärung oder eine Lösung auf Lager?

von tex (Gast)


Lesenswert?

Bei dieser Abwandlung endet das Programm nach der 10. Division?!

me = (me / 10.0)+1;

von Hannes Hering (Gast)


Lesenswert?

Hallo,

Das Problem mit der 3. Division liegt allein darin, das der dezimale
Bruch 0,1 nicht Binär dargestellt werden kann. Dafür kann weder der
Controller was, noch der Erfinder der Fließkommazahlen für Computer. D.
h. es ist eine "natürliche" Ungenauigkeit der Zahlendarstellungsweise.
Willst du solche Systemfehler umgehen, müsstest du entweder mit 2er
Potenzen rechnen (also 2 oder 4 oder 8 als Basis) oder aber du müsstest
deinen Code in BCD (Binary Coded Decimal) umwurschteln. Beides sehr
umständlich, vor allem die BCD-Version. Und mit den Potenzen is des so
ne Sache ... wie gesagt lassen sich manche (dezimal dagestellte) Zahlen
nicht in 2er Potenzen darstellen.

MFG

Hannes

von tex (Gast)


Lesenswert?

verstehe.
Dann manifestiert sich dieses Problem aber immer nur mit einem durchaus
konstanten Fehler, und sollte den 80537 mit der gleichen Ungenauigkeit
belastet haben?

von Hannes Hering (Gast)


Lesenswert?

So könnt ich mir das auch vorstellen. Vielleicht liegt es an der
Umsetzung des sprintf in den unterschiedlichen Bibliotheken. In der
alten Bibliothek hat es das Ergebnis "genauer" gerundet und die neue
Version rundet eben "ungenauer", sodass es jetzt auffällt, wenn nach
3 Stellen hinter dem Komma eine Ungenauigkeit auftritt. (Anm.: Ich hab
das Programm mal auf dem PC laufen lassen und da gibt das printf bzw.
sprintf den "richtigen" Wert aus, obwohl die Zahlen falsch im
Speicher stehen)

MFG

Hannes

von tex (Gast)


Lesenswert?

<obwohl die Zahlen falsch im Speicher stehen)>
Ich verstehe nicht. Warum stehen sie falsch im Speicher bzw. wie sieht
man das?
Und was passiert eigentlich bei
me = (me / 10.0)+1; ?
Warum sind die Ergebnisse da bereits nach der 10. Division
unterschiedlich?
Könnte ich das Problem mit einem teuren Compiler Compiler erschlagen?

von MSE (Gast)


Lesenswert?

@tex:

Weiß ich nicht! Aber Hersteller teurerer Compiler stellen einem diese
durch aus als Demo-Version zur Verfügung, damit man solche Fragen vor
dem Kauf klären kann. ;)

Ausserdem kann man bei Hersteller ja anfragen, wie es um die
Rechengenauigkeit ihrer Bibliotheken bestellt ist bzw. ob sie double
korrekt unterstützen.

Gruß, Michael

von Stefan May (Gast)


Lesenswert?

Hallo tex,

Ich glaube ein teurer Compiler wird Dir bei Deinem Problem nicht
helfen. Ich habe mal nach einem Dokument gesucht, welches die Probleme
mit Gleitkommazahlen bei der Berechnung im Computer erläutert. Es ist
leider nur in Englisch verfügbar, ich hoffe, das ist kein Problem.

http://docs.sun.com/source/806-3568/ncg_goldberg.html

Ich kann mir immer noch nicht vorstellen, was Du da tolles berechnest.
Aber wenn Du so eine hohe Genauigkeit benötigst, dann verwendest Du
meiner Meinung nach die falsche Plattform. Es gibt ja nicht umsonst
FPUs, die für die Berechnung von Gleitkomma-Zahlen entworfen wurden.

Wenn Du Dich näher mit dem Thema auseinandersetzen willst, dann schau
mal nach dem Standard IEEE754. Nach dieser Methode werden
Gleitkommazahlen in Binärer Form abgebildet. Wenn Du das obige Dokument
liest, dann werden Dir die Probleme bei Deinen Berechnungen auffallen.

mfg, Stefan.

P.S. Ich glaube Du versuchst nicht das Problem zu beheben, sondern nur
die Symptome.

von MSE (Gast)


Lesenswert?

@ Stefan May:

Eine FPU ist mitnichten nötig, um beliebig präziese zu rechnen! Sie ist
nur dann nötig, wenn dieses auch noch schnell gehen soll. Wie wir
bereits gehört haben, scheint es tex darauf nicht anzukommen.

Auch mich würde übrigens interessieren, um was es bei dieser Anwendung
geht.

Gruß, Michael

von peter dannegger (Gast)


Lesenswert?

"Ich glaube Du versuchst nicht das Problem zu beheben, sondern nur
die Symptome."


Das glaube ich auch.

Da alle mir bekannten µC-Compiler nur 32Bit floats können, sollte man
versuchen, die Formeln so umzustellen, daß sich die Fehler entweder
weitgehend kompensieren oder garnicht erst so weit aufschaukeln.


Eine andere Möglichkeit ist auch, die ganze Mathematik in Assembler zu
machen. Da ist es dann leicht, eine beliebig genaue Ganzzahlarithmetik
zu machen (80 Bit, 128 Bit oder was Du willst). Die Winkelfunktionen
müßte man dann auf die Grundrechenarten zurückführen.


Vorher sollte man aber erstmal prüfen, ob es auch wirklich daran liegt
und nicht an einem Speicherproblem (Stacküberlauf). Auch die 4kB können
schnell dahinfließen, wenn man irgendwo gemeine Rekursionen hat oder
versehentlich viele Konstanten (Texte) im SRAM definiert hat.

Dann gibt es auch noch das Mega103-Bit zu beachten, welches den
Speicher einfach mal verschiebt.


Peter

von Hannes Hering (Gast)


Lesenswert?

@tex:

>> obwohl die Zahlen falsch im Speicher stehen
> Ich verstehe nicht. Warum stehen sie falsch im Speicher
> bzw. wie sieht man das?

Ganz einfach: Die Zahlen werden ja im Speicher mit Exponent und
Mantisse dargestellt. Und bei einer 0,1 als Gleitkomma dargestellt
sieht die Mantisse in etwa so aus (double/52 Bit Mantisse):
1001 1001 1001 1001 1001 1001 1001 1001 1001 1001 1001 1001 1011
Hier sieht man, das in der letzten Stelle aufgerundet wurde, da der
Bruch eben nicht endlos lang werden kann. Den Exponenten weiss ich
jetzt net ganz genau, aber es trifft die Sache schon ganz gut. Ein
teurerer Compiler wird hier auf keinen Fall was bringen, weil es halt
Mathematisch schon nicht funktioniert. Ich würde auch die Methode von
Peter anraten, bei der die Formeln eben nicht für Menschen genau
ausrechenbar sein müssen, sondern für die Maschine.

MFG

Hannes

von tex (Gast)


Lesenswert?

Erst mal wieder vielen Dank euch allen. Im Prinzip komme ich ja mit den
38 Stellen der Float klar und der 80537 hat bewiesen, das es mit 8Bit
ja problemlos geht. Die Fehler liegen halt in meiner Software.
Ich sags nochmal. es ist nicht die genauigkeit, die mich in die floats
treibt. Bei der Berechnung treten halt nur Zahlen auf, die sich nur in
ab der 15. Nachkommastelle ändern. Weil diese zahlen in der Nächsten
Formel aber als ^2 ^3 ^4 ^5 wieder ienfließen ist ein winziger Fehler
im Vorhergehenden Wert in der nächsten Formel eine katastrophale
Abweichung. es geht um die Berchnung von Koordinaten im
dreidimensionalen Raum. Hast Du schon mal versucht eine Forelle im Bach
mit einem Speer zu fangen? Geht nicht, wegen der Lichtbrechung, wenn Du
keine Übung hast und nicht in der Lage bist den korrekten Blickwinkel
zu berechnen. Genauso kippst Du mit dem Fahrrad um, wenn Dein Gehirn in
der Kurve nicht den Winkel ausrechnen kann in der sich Zentifugalkraft
und Erdanziehung zu 0 addieren. Wenn also ein µC Fahrad fahren könne
soll muss er in der Lage sein, sowas auszurechnen. Klar. Sony und
Mitsubischi machen das mit Mega Aufwand mit FPUs. Ich habs mit 8 Bit
hinbekommen.

von Tobi (Gast)


Lesenswert?

"Ich habs mit 8 Bit hinbekommen."

fahrradfahren oder fische fangen?

von tex (Gast)


Lesenswert?

Liegt es an mir?

        double JD;

  D = 2454939 - 1534.063232;

  display_clear();
  display_cursor(1,1);
  sprintf(displaystring,"%-6.6f", (double)D);
        display_string(displaystring);

Das ausgegebene Ergebnis ist
      2453405.0000
Was mache ich falsch?

von Tobi (Gast)


Lesenswert?

evtl
D = (double)2454939 - 1534.063232;
bzw
D = 2454939.0 - 1534.063232;

von Matthias (Gast)


Lesenswert?

Hi

jetzt glaubs halt endlich:
Die Fließkommaimplementierung des AVRGCC unterstützt nur Zahlen mit
einfacher Genauigkeit (-> float). Dieses Format kann dank 23 Bit
Mantisse etwa 7 Dezimalstellen darstellen.

Matthias

von tex (Gast)


Lesenswert?

ja schon, aber mir gehen hier gerade ALLE Nachkommastellen flöten! Ich
wäre ja bei der Zahl oben schon froh, wenns denn 3-4 Nachkommastellen
wären.

von Stefan May (Gast)


Lesenswert?

Du hast eine Integer-Addition hingeschrieben. Wenn Du schreibst


x = 23 + 1.4

Dann ist das Ergebnis 24 und nicht 24.4, weil das Ergebnis der Addition
ein int ist. Du mußt hinschreiben

x = 23.0 + 1.4

Das hat Tobi schon geschrieben. Selbst wenn x ein double, float oder
was auch immer ist, dann ist das Ergebnis der Addition trotzdem ein
int.

ciao, Stefan.

P.S. siehe dazu auch K&R Einführung in C

von Tobi (Gast)


Lesenswert?

"wenns denn 3-4 Nachkommastellen wären."
bei floating point darstellungs sind vor- und nachkommastellen das
gleiche. du hast deine 7 stellen schon vor dem komma ausgereizt, da
bleibt für dahinter nix mehr über

von tex (Gast)


Lesenswert?

@Steffan
OK. Das war dann beim RC-Compiler anders. Wie muss ich es schreiben,
wenn der erste Summand der ganzzahlige Anteil einer Division ist, also
sagen wir mal   (signed long)(A/12.5) ? DA aknn ich ja nun kein .0
dransetzen.

@Tobi
Sorry, Dein Statement hatte ich nicht gesehen.

von Rufus T. Firefly (Gast)


Lesenswert?

@tex:

  (A / 12.5)

Was hier geschieht, hängt vom Datentyp der Variablen A ab.

Wenn das ein int ist, Du aber eine float-Division ausführen möchtest,
hilft ein Typecast:

  ((float) A / 12.5)

von tex (Gast)


Lesenswert?

nein nein, Noch mal die Frage:
Ich brauche als Ergebnis einer Addition eine Gleitkommazahl. Ein
Summand (z.b 2) sind jedoch gewollt Integer
Stelle ich mir dass dann so vor?

x = (float)((unsigned int)(A/12.5)) + 15.5

??

von SteffenM (Gast)


Lesenswert?

x=((float) 0.08*a+15.5)

von tex (Gast)


Lesenswert?

He he,
nicht schlecht
IAR-Compiler macht übrigens 64Bit floats

von Volkmar (Gast)


Lesenswert?

> Stelle ich mir dass dann so vor?
>
> x = (float)((unsigned int)(A/12.5)) + 15.5

Stell doch die 15.5 nach vorne:

x = 15.5 + ((unsigned int)(A/12.5))

Hierbei
> x=((float) 0.08*a+15.5)
ist (A/12.5) doch als float enthalten und nicht als Dein gewünschter
Integer.

Volkmar

von tex (Gast)


Lesenswert?

ich hab es vorwärts und rückwärts, mit und ohne (float) ... eingegeben,
mit und ohne Optimierung im Makefile das Ergebnis ist immer integer.
Ich habe keine Idee mehr.

von Matthias (Gast)


Lesenswert?

Hi

es ist kein Integer. Es ist ein float. float kann aber nur 7
Dezimalstellen darstellen. Wenn die schon vor dem Komma sind kommen
nach dem Komma einfach keine Zahlen mehr. Informier dich endlich über
die Funktionsweise von Fließkommazahlen. Dann wird dir auch klar was da
passiert.

Matthias

von Hannes Hering (Gast)


Lesenswert?

@tex: Was Matthias meint ist:

D = 2454939 - 1534.063232;
D = 2453405.0000

D hat eben schon 7 gültige Ziffern und lässt eben keine
Nachkommastellen mehr zu.

Hier ist dieses ominöse Problem mit den 7 gültigen Ziffern (eben NICHT
Nachkommastellen) sehr schön zu sehen. Die 32 Bit Floats können eben
nicht mehr! Auch mein Super-Hyper-Pseudo Visual Studio .NET 2003
Compiler für x86 rechnet nicht genauer als der 8-Bit AVRGCC. Ein
anderer Compiler der möglicherweise 64 Bit berechnet hat aber genau das
gleiche Problem:
Du hast möglicherweise ne Zahl, die 5 Stellen vor dem Komma hat, dann
kannst du eben auch nur 10 Stellen hinter dem Komma noch genau
darstellen. Von dem her ...

Wie schon gesagt müsstest du für dein spezielles Problem mit der
Genauigkeit der Zahlendarstellung eine eigene Mathe-Bibliothek
schreiben, die eine höhere Stellenzahl aufweist. (Z. B. die 80
Bit-Variante, die in x86 kompatiblen FPUs verwendet wird)

MFG

Hannes

von thkais (Gast)


Lesenswert?

Oder, wie schon einmal kurz angesprochen, eine BCD-Arithmetik. Das ist
die einzige Möglichkeit, Dezimalzahlen fehlerfrei darzustellen. Viele
Warenwirtschaftsprogramme arbeiten damit, da sonst bei der Berechnung
von Rabatten nur Müll herauskommt.
Ein sehr interessanter Artikel:

http://www.3dcenter.de/artikel/fp_format/

Zwar gehts hier um Grafikkarten und die genutzten Zahlenformate, aber
das ist eine sehr informative Seite. Dort werden verschiedene Fix- und
Gleitkommatypen beleuchtet und die Vor- und Nachteile diskutiert.

von tex (Gast)


Lesenswert?

@ Matthias
Sorry! Bin ein bisschen begriffsstutzig die Tage. Ich hatte meine
C-Buch Definition 3.4Exp-38 noch im Hinterkopf, was sich ziemlich genau
mit meinem Versuch von oben deckte und wollte Dir nicht so recht
glauben,
Ich tue hiermit Buße.

Inzwischen ist das Problem klar. Ich werde mal versuchen, ob ich es
umgehen kann, aber ich finde es gotterbärmlich, dass mein kleiner
billiger 0815 RC-Compiler, der mit Sicherheit schon uralt war, als ich
ihn vor 10 Jahren für mein Projekt bemühte, ganz locker 64Bit Variablen
konnte und die neueste Evolution auf dem µC-Markt 10 Jahre später, mit
Debugger und gigantischen Make-Files, die das 1000fache an Speicher und
Rechnerperformance frisst, einen erbärmlichen Bruchteil dessen leistet,
was das Uraltprodukt hergab.
Mit der Technik von heute hätte ich mein Projekt von vor 10 Jahren
nicht realisieren können.

Ich schau mich mal nach etwas ausgegoreneren Compilern um, weil die
Lösung mit der Zahlenumstellung nur ein Notlösung sein kann.
Das Teil von IAR hab ich schon, also die Demoversion, die kann zwar
meine 64bit, aber glücklich bin ich damit nicht so recht. Die
Lizenzanbindung am meinen Rechner, wo ich mir alle halbe Jahre ein
neues Notebook gönne, ist rottig. Außerdem bekomme ich einfach nichts
damit zusande, was ich in meinen Prozessor schieben kann? Ich zu doof
oder Programm zu doof?

Also wenn jemand eine Nette Idee für einen Compiler hat, der sich nicht
an einer Double-Variablen verschluckt, ...

Und noch einmal vielen Dank an alle die mir hier so nett geholfen
haben.

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.