Hallo miteinander,
ich habe ein etwas mystisches Problem mit Fließkomma-Berechnungen.
Bevor nun jemand die Glaskugel hervorkramen muss: ;-)
- Prozessor: ADuC834
- Compiler: KEIL: C51.exe X3.35 vom 21.12.1992
- Linker: KEIL: L51.exe V2.8 vom 2. 1.1991
- Libraries: KEIL: C51S.lib und C51FPS.lib vom 23. 9.1991
- Pragmas: code symbols small regparms
Die Firmware macht folgendes:
- eine Temperatur (float!) messen und in bestimmten Abständen (ca. 10
Sek.) im Flash speichern (float!)
- nach jeder Temperatur-Messung folgende Berechnung ausführen:
y += P1 hoch (AT - P2)
'y' ist eine globale Variable und wird bei Start der Messung auf 0
gesetzt. P1 und P2 sind zwei globale Parameter (float!), die während der
Messung konstant sind. AT ist die aktuell gemessene Temperatur (float!).
P1 liegt so bei 1.2F und P2 bei 50.F
der Source-Code dazu ist:
1
y+=pow(P1,(AT-P2));
am Ende der Messung wird 'y' gespeichert und zur PC-Software übertragen.
Auf dem PC läuft eine ebenfalls von mir geschriebene Windows-Software
(geschrieben mit Microsoft Visual Studio 2008, C++),
die nun alle gespeicherten Temperaturwerte aus dem Flash des ADuC834
ausliest (über RS232) und auf Harddisk speichert.
Lasse ich nun die PC-Software 'y' berechnen (alles in float!):
1
y=0;
2
for(i=0;i<maxwerte;i++){
3
y+=pow(P1,(T[i]-P2));// T[i] ist die Temperaturmessreihe!
4
}
so kommt bei einer Messreihe mal der gleiche Wert wie im ADuC835, bei
einer anderen Messreihe aber auch ein stark abweichender (ca. 30%
höherer) Wert heraus.
In Excel transferierte Messreihen ergeben dort immer den gleichen Wert
für 'y' wie in meiner Windows-Software, so dass ich den Rechenfehler im
ADuC834 vermute.
Hat jemand schon Erfahrung mit der Rechengenauigkeit der
Keil-Floating-Point-Emulation?
Könnte es sein, dass bei sehr kleinen Exponenten
(Temperatur-Differenzen) oder negativen Exponenten die Keil-Library
schwächelt?
Viele Grüße
Peter
Du zeigst keinen Sourcecode, sondern nur komplett nichtssagende
Schnipsel.
Davon abgesehen wird die Genauigkeit der FP-Routinen für Deinen 8051
nicht der des PCs entsprechen; höchstwahrscheinlich ist ein float 32
Bit groß (statt 64 wie auf dem PC).
Oder noch kleinere float-Typen.
Das aber ist nicht das Problem, denn auch mit geringen Genauigkeiten
kann man noch rechnen, wenn man sich ein paar Gedanken über die
Reihenfolge der Operationen macht.
Generell: Additionen/Substraktionen nach Multiplikation/Division wenn
sich der Term umstellen lässt. (siehe Auslöschungen und co
http://de.wikipedia.org/wiki/Gleitkommazahl#Ausl.C3.B6schung )
Also statt
> Compiler: KEIL: C51.exe X3.35 vom 21.12.1992
Recht alte Version, aber eigentlich noch gut einsetzbar.
Versuch doch mal die betreffenden Funktionen mit einen anderen Compiler
zu testen. zB. SDCC oder uc51, welche auch Float in der Demoversion
unterstützen.
Float ist bei Keil (V3) 4 Byte groß, (+-1,176E-38 bis +- 3,40E+38)
IEEE-54 Standard
Im Handbuch zu Version 3 steht einiges zu den Besonderheiten von
float-Berechnungen, ua. auch, wie Fehler bei Berechnungen abgefangen
werden können.
>X3.35
Ich habe mal V3.20 und V3.40 aufgerufen. Beide melden ein Vn.nn Ist
Deine Version tatsächliche eine Xn.nn?
Vielleicht ist die in ihren Möglichkeiten 'abgemagert'.
>X3.35
Stimmt, X habe ich auch noch nicht gesehen.
Nutzt Du manchmal Float-Berechnungen im Interrupt und Hauptprogramm?
Wenn ja, musst Du bei Keil in der Interruptfunktion vorher den
Float-Status sichern und wiederherstellen.
Hallo an alle,
vielen Dank für die schnellen Antworten.
Maxxie schrieb:
> Also statt y += pow(P1, (AT - P2));lieber y += pow(P1, AT) / pow(P1, P2));> Erhöht den Rechenaufwand, reduziert den Fehler.
dass ist doch schon mal ein brauchbarer Hinweis. Trotz 30 Jahren
Programmiererfahrung ist mir dieser Umstand neu. Aber gut man, lernt ja
nie aus ;-)
Dass mit dem X hätte ich lieber nicht schreiben sollen ;-) Denkt Euch
einfach anstelle des X ein V.
Mathias K. schrieb:
> Nutzt Du manchmal Float-Berechnungen im Interrupt und Hauptprogramm?
Nein, es wird nur im Main gerechnet.
Rufus t. Firefly schrieb:
> Davon abgesehen wird die Genauigkeit der FP-Routinen für Deinen 8051> nicht der des PCs entsprechen; höchstwahrscheinlich ist ein float 32> Bit groß (statt 64 wie auf dem PC).
Meines Wissen entspricht der 'float' beim MS Compiler dem IEEE-Standard
(also 32-Bit). Ich habe zum Vergleich im meinem Windows-Programm die
Berechnung mit 'float' und einmal mit 'double' durchlaufen lassen und
eine Abweichung war nur in der 6. Nachkommastelle zu erkennen.
Von daher denke ich nicht, dass es die Genauigkeit (32- oder 64-Bit)
ist, sondern die verwendeten Berechnungs-Algorithmen. Auf dem PC hat man
einen ziemlich guten Co-Prozessor, der ja heutzutage im Vergleich zum Co
beim Intel-386er richtig rechnen sollte ;-)
Grüße
Peter
Peter D. schrieb:
> Auf dem PC hat man einen ziemlich guten Co-Prozessor,
Wo? Heutzutage ist die FPU im Prozessor integriert?
> der ja heutzutage im Vergleich zum Co beim Intel-386er richtig rechnen sollte
;-)
Was hast Du am 80x87 auszusetzen?
Iwan
Hallo Ivan,
gehen deine Fragen nicht etwas am Thema vorbei?
Ivan schrieb:
> Wo? Heutzutage ist die FPU im Prozessor integriert?
Das ist doch nun Korinthen-Kackerei, ob der mathematische Prozessor
intern oder extern sitzt. Es ging doch nur darum, dass heutzutage im PC
schon lange nicht mehr mit Fließkomma-Emulatoren gerechnet wird.
Ivan schrieb:
> Was hast Du am 80x87 auszusetzen?
Nichts, aber es gab mal ein Gerücht, dass der 80387 nicht "richtig"
rechnen würde. Zwar nur unter ganz speziellen und schwer herzustellenden
Bedingungen. Viel habe ich dazu im Web nicht gefunden, aber z.B.:
http://www.heise.de/ct/artikel/Prozessorgefluester-285634.html
Aber, wie schon gesagt, dieser Beitrag ist OffTopic!
Grüße
Peter
Der war aber bereits bei der integrierten Pentium FPU. P60 und P66,
nicht in den 80x87-Chips, welche externe FPUs waren.
Die errate waren damals noch lang nicht so öffentlich bei Intel und co,
wie sie heute sind. Der FDIV -Bug war da einer der Weckrufe für deren
breite Offenlegung. Man muss bei einigen Prozessor-Bugs früher oft immer
noch bei "Gerücht" bleiben.
Es gab doch sogar noch Wettbewerbe darum, wer als erster "verheimlichte"
Opcodes findet und richtig interpretiert. (wie z.B. LOADALL)