MEGA 128 verrechnet sich

Gast #142895
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
Gast #142898
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.
Gast #142900
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?
Gast #142902
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...
Gast #142904
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.
Gast #142905
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
Gast #142906
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?
Gast #142908
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;


    }
Gast #142911
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.
Gast #142912
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.
Gast #142913
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.
Gast #142915
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.
Gast #142916
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?
Gast #142917
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.
Gast #142918
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
#142919
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
Gast #142920
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.
Gast #142921
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.
Gast #142922
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-
Gast #142923
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
Gast #142924
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?
Gast #142925
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.
Gast #142928
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.
Gast #142929
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.
Gast #142930
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.
Gast #142931
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.
Gast #142932
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
Gast #142933
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?
Gast #142934
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 ;-)
Gast #142935
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.
#142936
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
Gast #142937
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.
Gast #142938
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?
Gast #142940
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
Gast #142942
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
Gast #142943
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?
Gast #142944
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
Gast #142945
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.
Gast #142946
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
Gast #142947
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
Gast #142948
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
Gast #142949
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.
Gast #142951
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?
Gast #142953
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
Gast #142955
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
Gast #142956
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
Gast #142957
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.
Gast #142958
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)
Gast #142959
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

??
Gast #142962
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
Gast #142964
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
Gast #142965
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
Gast #142966
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.
Gast #142967
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.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren