Forum: Compiler & IDEs GCC Berechnungen auf dem PC abweichend


von Robert (Gast)


Lesenswert?

Gute Tag!

Zu folgender Frage hoffe ich hier auf Hilfe.

Stand der Dinge:
Ich habe mir ein eigentlich sehr einfaches aber mit der Zeit doch 
gewachsenes Programm zur Steuerung meines Helikopters geschrieben. Die 
Befehle werden in Sequenzen abgelegt, welche ein hohes Maß an 
Berechnungen mit Gleitkommazahlen benötigen, welche dann einfach auf 
einer SD-Card gespeichert werden. Festpunktrechnung ist hier nicht 
möglich.

Idee:
Da die Rechenzeit auf dem ja für Gleitkommaberechnung nicht sehr 
geeigneten Atmega328 nun doch schon etwas länger dauern, wollte ich 
diese einfach auf dem PC berechnen lassen und die fertig berechneten 
Daten auf die SD-Card speichern. Verwendet habe ich hierzu den GCC für 
Windows.

Problemstellung:
Die Ergebnisse der Berechnungen mit exakt dem selben C++ Code auf dem 
PC/GCC unterscheiden sich signifikant von jenen, welche direkt auf dem 
Atmel berechnet wurden. Es scheint, als wären die Berechnungen auf dem 
PC wesentlich genauer, was aber nicht gewünscht ist, da der Atmel mit 
den auf dem PC vorausberechneten Zwischenwerten, auf seine "ungenaue Art 
und Weise" weiter rechnen muss.

Letztlich nun meine Frage:
Wie lässt sich auf dem PC die Art und Weise, wie der Atmel die 
Berechnungen durchführt, simulieren? So, dass beide Ergebnisse, von PC 
und vom Atmel, exakt übereinstimmen? Leider finde ich hierzu nichts in 
Google.

Freue mich auf Hilfe und danke im Voraus.

von Max (Gast)


Lesenswert?

Die Numerik lässt grüßen, würde ich behaupten.
Du rechnest ja einmal auf einer 8 bit Maschine und dann auf einer 32 
oder 64 bit Maschine. Wie gravierend sind denn die Unterschiede? Nicht 
das es doch an deinem Programm liegt.

von nicht "Gast" (Gast)


Lesenswert?

Ein Standard-Test für Gleitkommarechnungen ist: e^pi-pi und dann das 
Ergebnis mit 20 vergleichen.

von Peter II (Gast)


Lesenswert?

rechnest du mit double?

Denn im Atmel ist double = float und damit recht ungenau. Im PC nicht.

von Robert (Gast)


Lesenswert?

Danke, bis hier her!

Und danke für den Test, aber die Abweichung ist ja bereits bewiesen.

Ich rechne nur mit Float, kein Double.

Ich denke, dass es das ist, was Max schreibt 8bit gegen 64bit. Die 
Abweichungen sind nicht groß aber leider zu groß.

Gibt es einen Compiler switch den ich übersehen habe, damit der GCC auf 
dem PC ebenfalls mit 8bit Logik kompiliert? Kann man man eventuell 
WINAVR irgendwie dazu bewegen, ein kleines Programm mit 8bit Logik für 
den PC zu kompilieren?

von Peter D. (peda)


Lesenswert?

Du mußt auf dem PC alle Rechnungen als float machen, dann sollte das 
gleiche rauskommen, wie auf dem MC.
Also auch alle Zwischenergebnisse wieder als volatile float speichern.

von Peter II (Gast)


Lesenswert?

Robert schrieb:
> Ich denke, dass es das ist, was Max schreibt 8bit gegen 64bit

nein das ist Unsinn. Man kann auch auf einem 8bit System mit 64bit 
variablen rechnen. Es muss dort genau das gleiche rauskommen.

von Karl H. (kbuchegg)


Lesenswert?

Und nur zur Verdeutlichung.
Mit float (4 Byte) hast du so um die 5 bis 6 signifikante Stellen. Mit 
double (8 Byte) sind es aber bereits deren 14 bis 15.

signifikante Stellen sind nicht dasselbe wie Nachkommastellen! 
signifikante Stellen sind alle Stellen zusammen. Hast du also die Zahl 
1234.567 dann ist nach der 2.ten Nachkommastelle Schluss. Du hast 4 
Stellen vor dem Komma, d.h um auf 6 signifikante Stellen zu kommen 
kannst du noch 2 Nachkommastellen mit dazu nehmen. Alles dahinter (also 
die 7) ist mehr oder weniger gelogen. Und je mehr du dann mit den Zahlen 
rechnest und sie weiter bearbeitest, desto schlimmer wird es. Kleine 
Fehler, die sich aus der nicht Darstellbarkeit der korrekten Zahl 
ergeben, summieren sich auf und haben die Tendenz erst mal eher klein zu 
bleiben ehe sie dann recht schnell anwachsen. D.h. nach ein paar 
Berechnungen hast du keine 5 oder 6 signifikanten Stellen mehr sondern 
nur noch 4 bis 5.

Daher auch der große Unterschied zu double (auch wenn das Problem dort 
im Grund nicht anders ist). Es macht eben einen UNterschied, ob ich nach 
20 Berechnungen nur noch 4 signifikante Stellen (vertrauenswürdige 
Stellen) habe, oder deren 14.

von Dr. Sommer (Gast)


Lesenswert?

Robert schrieb:
> Ich denke, dass es das ist, was Max schreibt 8bit gegen 64bit. Die
> Abweichungen sind nicht groß aber leider zu groß.
8Bit-Float gibts nich so wirklich... Vermutlich hast du mit "int" und 
"short" etc. gerechnet, was am PC eine andere Größe als am AVR hat. 
Verwende Typen wie uint16_t aus der <cstdint>.

nicht "Gast" schrieb:
> Ein Standard-Test für Gleitkommarechnungen ist: e^pi-pi und dann
> das
> Ergebnis mit 20 vergleichen.
ehehehe... http://xkcd.com/217/

von Oliver (Gast)


Lesenswert?

Robert schrieb:
> Ich rechne nur mit Float, kein Double.

Du schon, aber der Prozessor in deinem PC nicht. Der rechnet trotzdem 
mit sehr viel mehr Bits, und daher kommen wohl die Unterschiede.

Es gibt die Compileroption -mpc32. Vielleicht hilft das, ich habs aber 
nie ausprobiert.

Oliver

von Davis (Gast)


Lesenswert?

nicht "Gast" schrieb:

> Ein Standard-Test für Gleitkommarechnungen ist: e^pi-pi und dann das
> Ergebnis mit 20 vergleichen.

Was sagt das Ergebnis 19,99909998 aus?

von Peter II (Gast)


Lesenswert?

Oliver schrieb:
> Du schon, aber der Prozessor in deinem PC nicht.

das spielt keine rolle. Wenn man float will, dann wird die Rechnung auch 
in float gemacht, egal wie die CPU intern rechnet.

von Karl H. (kbuchegg)


Lesenswert?

Peter II schrieb:

> das spielt keine rolle. Wenn man float will, dann wird die Rechnung auch
> in float gemacht, egal wie die CPU intern rechnet.

Das kommt zum Teil aber auch darauf an, wie die Berechnung 
niedergeschrieben wurde. Ob der COmpiler alle Zwischenergebnisse aus der 
80 Bit FPU holt und erst mal wieder auf 32 Bit Floats zurechtstutzt, ehe 
dann damit weiter gerechnet wird, oder ob er das nicht tut und erst das 
Endergebnis aus der FPU von 80 Bit auf 32 Bit reduziert um es dann in 
einem float zu speichern.

von Peter II (Gast)


Lesenswert?

Karl Heinz Buchegger schrieb:
> Das kommt zum Teil aber auch darauf an, wie die Berechnung
> niedergeschrieben wurde. Ob der COmpiler alle Zwischenergebnisse aus der
> 80 Bit FPU holt und erst mal wieder auf 32 Bit Floats zurechtstutzt, ehe
> dann damit weiter gerechnet wird, oder ob er das nicht tut und erst das
> Endergebnis aus der FPU von 80 Bit auf 32 Bit reduziert um es dann in
> einem float zu speichern.

sicher? Ich hätte vermutet das er immer das Zwischenergebnis auf float 
casten muss. Weil sonst je nach cpu etwas anderes rauskommt.

von Quak (Gast)


Lesenswert?

Robert schrieb:

> Festpunktrechnung ist hier nicht möglich.

Festpunktrechnung ist immer moeglich, zur Not halt mit wechselnden 
Bereichen.

> Es scheint, als wären die Berechnungen auf dem
> PC wesentlich genauer, was aber nicht gewünscht ist, da der Atmel mit
> den auf dem PC vorausberechneten Zwischenwerten, auf seine "ungenaue Art
> und Weise" weiter rechnen muss.

Wenn du ein Problem mit zu genauen Ergebnissen hast, hast du grossen 
Murks produziert. Mir entsteht der Eindruck, du hast deine Algorithmen 
schon lange nicht mehr im Griff und deswegen schmeisst dich jede 
Abweichung aus der Bahn. Aber gut, wenn du den Murks unbedingt brauchst: 
Mach die Vorbereitung der SD-Karte halt auf einem zweiten AVR.

von Oliver (Gast)


Lesenswert?

Peter II schrieb:
> sicher? Ich hätte vermutet das er immer das Zwischenergebnis auf float
> casten muss. Weil sonst je nach cpu etwas anderes rauskommt.

Kommt es ja auch, daher das Problem des TO.

Lies dir spaßeshalber mal diese Seite durch:

http://gcc.gnu.org/onlinedocs/gcc/i386-and-x86_002d64-Options.html

und überlege, warum es da ein paar hilfreiche Compileroptionen zu dem 
Thema gibt.

Oliver

von Karl H. (kbuchegg)


Lesenswert?

Peter II schrieb:

> sicher? Ich hätte vermutet das er immer das Zwischenergebnis auf float
> casten muss. Weil sonst je nach cpu etwas anderes rauskommt.

Ich hab da jetzt ehrlich gesagt schon lange nicht mehr im Standard 
nachgesehen. Würde mich aber wundern, wenn sich da etwas grundlegendes 
geändert hätte: Da im Standard nicht definiert wird, wie Floating Point 
Arithmetik zu funktionieren hat und schon gar nicht welches System zu 
benutzen ist, denke ich: ja - das ist so. Da kommt auf jeder FPU etwas 
anderes raus, je nachdem wie die FPU tatsächlich arbeitet. Das war zb 
mit dem Microsoft Compiler (früher, heute weiß ich es nicht) ein 
mögliches Problem, als die FPU's noch nicht sehr verbreitet waren. Je 
nachdem, ob man eine FPU hatte oder nicht, kriegte man leicht 
unterschiedliche Ergebnisse. Da man aber Floating Point rechnen sowieso 
nie ohne ein ausreichend bemessenes Epsilon macht, war das dann so 
tragisch auch wieder nicht, ob sich die Ergebnisse in der 14.ten 
signifikanten Stelle unterschieden oder nicht. Gerade bei CAD Sachen 
sind derartige Dinge unangenehm: Gibt es noch einen schleifenden 
Schnitt, oder sind 2 Gerade parallel? Liegt der Punkt in einer Ebene 
oder doch schon darüber oder darunter? Sind 2 Punkte tatsächlich 
identisch, etc.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Robert schrieb:
> Wie lässt sich auf dem PC die Art und Weise, wie der Atmel die
> Berechnungen durchführt, simulieren?

Anstatt "Atmel" meinst du wohl "avr-gcc"?

Letzterer verwendet für solche Berechnungen zur Compilezeit MPFR:

   "The MPFR library is a C library for multiple-precision
    floating-point computations with correct rounding."

http://www.mpfr.org

Falls dein Programm nicht funktioniert, falls Berechnungen zu genau 
sind, hast du m.E. ein ganz anderes Problem.

von Amateur (Gast)


Lesenswert?

Bei einem PC lässt sich die größere Genauigkeit fast nicht vermeiden - 
klingt komisch - ist aber so.
Da es heute praktisch keinen PC ohne FPU mehr gibt, der Compiler dies 
auch weiß, wird oft darauf optimiert. D.H. auch wenn die Übergabe in 
kürzerem Format erfolgt, so wird intern oft mit 80 Bit gerechnet. Bleibt 
ein unnötiges Zwischenergebnis in der FPU, so erfolgen zwei aufeinander 
folgende Rechnungen u.U. mit 80 Bit ohne zwischenzeitliche 
Rückkonvertierung. Das aber geht nicht ohne eine erhöhte Genauigkeit.

von Walter T. (nicolas)


Lesenswert?

nicht "Gast" schrieb:
> e^pi-pi und dann das
> Ergebnis mit 20 vergleichen

Scherzkeks. http://xkcd.com/217/

von Davis (Gast)


Lesenswert?

Nicolas S. schrieb:
> nicht "Gast" schrieb:
>> e^pi-pi und dann das
>> Ergebnis mit 20 vergleichen
>
> Scherzkeks. http://xkcd.com/217/

Spielverderber.

von Robert (Gast)


Lesenswert?

Zunächst vielen Dank, dass Sie alle Sich heute meinen Kopf zerbrochen 
und meine Befürchtungen, dass es von der Hardware abhängt, bestätigt 
haben.

Ich werde mir die von Johann L. empfohlene MPFR lib ansehen. Wenn ich 
richtig verstehe, bildet die lib Fließkommaberechnung in Software ab, 
was dann eigentlich zu Plattform unabhängig gleichen Ergebnissen führen 
sollte. Ist dies so, wäre meine Frage beantwortet.

von Rolf Magnus (Gast)


Lesenswert?

Peter II schrieb:
> Karl Heinz Buchegger schrieb:
>> Das kommt zum Teil aber auch darauf an, wie die Berechnung
>> niedergeschrieben wurde. Ob der COmpiler alle Zwischenergebnisse aus der
>> 80 Bit FPU holt und erst mal wieder auf 32 Bit Floats zurechtstutzt, ehe
>> dann damit weiter gerechnet wird, oder ob er das nicht tut und erst das
>> Endergebnis aus der FPU von 80 Bit auf 32 Bit reduziert um es dann in
>> einem float zu speichern.
>
> sicher? Ich hätte vermutet das er immer das Zwischenergebnis auf float
> casten muss. Weil sonst je nach cpu etwas anderes rauskommt.

Ja, aber das wäre auch ein großer Performance-Verlust, weil dazu der 
Wert nach jeder Teilrechnung erst in den Speicher geschrieben und wieder 
gelesen werden muss. Mit entsprechenden GCC-Optionen kann man aber dafür 
sorgen, daß das tatsächlich getan wird.
Aus der GCC-Doku:

**********************************************************************
-ffloat-store
Do not store floating-point variables in registers, and inhibit other 
options that might change whether a floating-point value is taken from a 
register or memory.
This option prevents undesirable excess precision on machines such as 
the 68000 where the floating registers (of the 68881) keep more 
precision than a double is supposed to have. Similarly for the x86 
architecture. For most programs, the excess precision does only good, 
but a few programs rely on the precise definition of IEEE floating 
point. Use -ffloat-store for such programs, after modifying them to 
store all pertinent intermediate computations into variables.
**********************************************************************

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Robert schrieb:
> Die
> Befehle werden in Sequenzen abgelegt, welche ein hohes Maß an
> Berechnungen mit Gleitkommazahlen benötigen, [...]

Kannst Du mal ein Beispiel nennen? Ich kann mir beim besten Willen nicht 
vorstellen, wo und warum Du Gleitkommazahlen brauchst.

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.