PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Rechenfehler



surfer
20.11.2005, 13:37
Ich berechnen einen Wert mit float Zahlen...
Wenn ich ihn in einen string mit dtostrf wandeln will, gibt es immer einen Rundungsfehler...


char ausgabe[20];
float r=6537.137;

dtostrf(r,4,4,ausgabe);
disp_text(ausgabe);

Dann wird der Wert 6537.1371 Ausgegeben...
auch wenn ich die zahl 6537.13700000 in die Variable schreibe, bringt er mir 6537.13711111111111 ????
Mit der Zahl 6000.2000 funktioniert es tadellos?

Ist für solche Zahlen float nicht geeignet?
Habe auch schon folgendes versucht:
sprintf(ausgabe,"%f",r);
aber da gibt es eine warnung wegen double und ein ? wird ausgegeben...

Irgendwelche Tipps?

Merci

PicNick
20.11.2005, 13:41
Es gehen nicht alle Zahlen. Kämpfe dich mal durch die verschiedenen Application-Notes.
Besonders heikel ist das beim Vergleichen auf "equal"

SprinterSB
20.11.2005, 14:15
Ein float wird intern durch 32 Bit repräsentiert, damit sind logischerweise nicht allen reelen Zahlen darstellbar.

Insbesondere gelten -- wie von Robert schon angesprochen -- *nicht* die von den reelen Zahlen vertrauten Rechenregeln!

So ist i.a

a+(b+c) != (a+b)+c
a*(b*c) != (a*b)*c
a*(b+c) != a*b+a*c

etc. und besonders tückisch:

a != b folgt nicht a-b != 0, was zu Laufzeitfehlern beim Dividieren füren kann:

if (a != b)
quot = 1.0 /(a-b); // *AUTSCH*, Divisor kann 0 sein !!!

Weil maximal 2^32 verschiedene reele Zahlen darstellbar sind, gibt es zwischen den Zahlen immer Lücken. Diese Lücken werden um so größer, je größer die darzustellenden Zahlen betragsmässig sind.

skillii
20.11.2005, 16:10
Ich versuche immer wenn es irgendwie möglich ist Gleitkommadatentypen zu vermeiden ...
Sie sind neben den den Tücken die SprinterSB genannt hat auch noch sehr langsam!!! (Nicht die Datentypen sondern die Operationen mit ihnen :mrgreen: )

mfg

surfer
22.11.2005, 21:11
Also Danke mal für die Antworten!

1. Soll das etwa heissen, dass mein ATMEL zu "dumm" ist um diverse Trigonometrische funktionen GENAU auszurechnen?
Das wäre wirklich seeehr schade, da ich an einem GPS-Vermessungsgerät arbeite... Ich kann mir nicht so ganz vorstellen dass dies so ist, da diese Controller in vielen Kundenanwendungen (unserer Kunden) gebraucht werden, die wohl auch um einiges komplexer sind (Funkempfänger mit extrem genauen RSSID Ausgängen).

2. Oder liegt es nur an den Zahlentypen? Kann man da ein anderes Format benutzen?

Huiuiui.... Am Schluss muss ich das noch mit dem PC machen!

izaseba
22.11.2005, 21:56
Soll das etwa heissen, dass mein ATMEL zu "dumm" ist um diverse Trigonometrische funktionen GENAU auszurechnen?

Bedenke, daß der AVR nur addieren,subtrahieren,durch 2 dividieren, und mit 2 Multiplizieren kann, das wars.
Versuche jetzt damit trigonometrische Funktionen zu berechnen.
AVR != x86

Gruß Sebastian

linux_80
22.11.2005, 22:21
Hallo,
er kann sogar multiplizieren, aber nur zwei 8-bit Ganzzahlen miteinander,
aber dafür mit und ohne Vorzeichen.

Fliesskommazahlen müssen per selbstgebaute Methoden berechnet werden,
denn der AVR selber kann das so nicht.

Zum x86 gibts noch zu sagen, das dieser sogar einen CoPro braucht, wenns genauer werden soll.

stochri
22.11.2005, 22:21
Soll das etwa heissen, dass mein ATMEL zu "dumm" ist um diverse Trigonometrische funktionen GENAU auszurechnen?

Wieso ungenau ? Fließkommazahlen haben die Eigenschaft, einen relativen Fehler zu haben ( abhängig vom gewünschten Zahlenwert ).

In Deinem Beispiel:
Der relativer Fehler zwischen 6537.13700000 und 6537.13711111111111 ist ungefähr 0.0000001 Prozent. Mit der Genauigkeit kannst Du mit einem Metermaß keine Länge abmessen.
Wenn Du eine größere Genauigkeit brauchst, musst Du von Single Precission auf Double Precission wechseln. Ich weiss allerdings nicht, ob die Double Routinen in der AVR-Lib definiert sind.

Gruss,
stochri

izaseba
22.11.2005, 23:07
er kann sogar multiplizieren, aber nur zwei 8-bit Ganzzahlen miteinander,
aber dafür mit und ohne Vorzeichen.

Bist Du Dir sicher ?
Mit welchem Befehl geht das ?
Soweit ich weiß geht das nur mit Bits linksschieben und da hätte man nur die Zweierpotenzen im Angebot.
Das einzigste mit Vorzeichen wäre dann asr also arithmetisch rechts schieben, aber ich sehe da keinen Zusammenhang.
Ich schau mir nochmal den Befehlsatz an :-k

linux_80
22.11.2005, 23:14
mit diesem Befehl:
MUL Rd,Rr
ergebnis steht dann in R1:R0
:-b

zumindest steht der beim Mega8 mit dabei.
So ein Datenblatt macht schon was her 8-[

recycle
22.11.2005, 23:19
1. Soll das etwa heissen, dass mein ATMEL zu "dumm" ist um diverse Trigonometrische funktionen GENAU auszurechnen?

Ich habe da so grundsätzlich meine Zweifel ob ein schlauer Controller dem binären Zahlensystem mehr oder andere Werte entlocken kann als ein dummer ;-)
Mit einer Auflösung von x Bit lassen sich nunmal nur 2^x Werte darstellen, egal wie schlau man sich anstellt.



Huiuiui.... Am Schluss muss ich das noch mit dem PC machen!
Dann hoffe ich mal, dass du dich nicht irgendwann wundern musst, dass der dieselben Rechenfehler einfach nur etwas schneller macht ;-)

izaseba
22.11.2005, 23:32
MUL
MULS
MULSU

:oops:


zumindest steht der beim Mega8 mit dabei.
So ein Datenblatt macht schon was her

Sag ich doch immer wieder :oops:
Schon wieder was neues gelernt

Gruß Sebastian

EDIT: Scheint aber nur bei den Megas zu sein.

Vogon
22.11.2005, 23:55
Oder liegt es nur an den Zahlentypen? Kann man da ein anderes Format benutzen?
Wikipedia sagt: http://de.wikipedia.org/wiki/Gleitkommazahl
... bilden die Gleitkommazahlen eine endliche Arithmetik, die vor allem im Hinblick auf numerische Berechnungen mit Computern entwickelt wurde. Dort dienen die Gleitkommazahlen meist als rationale Näherungen für reelle Zahlen.

linux_80
23.11.2005, 00:24
Scheint aber nur bei den Megas zu sein.

deshalb wird er wohl nicht so oft verwendet.

Müsste man mal probieren, ob der gcc diesen verwendet, und ob man dazu die richtige C-Formel zusammenbringt.

Klaus_0168
23.11.2005, 01:06
Hi all,


Scheint aber nur bei den Megas zu sein.

deshalb wird er wohl nicht so oft verwendet.

Müsste man mal probieren, ob der gcc diesen verwendet, und ob man dazu die richtige C-Formel zusammenbringt.
Das Problem mit den Rechenfehlern ist ein systematischer Fehler, der vom verwendeten binären Zahlensystem verursacht wird. Bei einer Umwandlung der Zahl 80 in eine Gleitkommazahl wird die 80 in 0.8 x 10e2 umgewandelt.

Nach IEEE 754 ( http://de.wikipedia.org/wiki/Flie%C3%9Fkommazahl ) wird eine Gleitkommazahl im Singleformat mit 23Bit Mantisse und 8Bit Exponent dargestellt.
Die 0.8 wird in 11001100110011001100110 00000010 umgewandelt (0.79999995231 -> 79.999995231).

Binär gesehen ist 0.8 eine irrationale Zahl. Damit ist der Rechenfehler schon vorprogrammiert ohne Chance korrigiert werden zu können.

Grüße Klaus

SprinterSB
23.11.2005, 09:51
...auch wenn ich die zahl 6537.13700000 in die Variable schreibe, bringt er mir 6537.13711111111111 ????

Ist für solche Zahlen float nicht geeignet?
Habe auch schon folgendes versucht:
sprintf(ausgabe,"%f",r);
aber da gibt es eine warnung wegen double und ein ? wird ausgegeben...

Irgendwelche Tipps?

Bei Verwendung von float hast du bei den angegebenen Werten einen relativen Fehler von ca 1.7*10^{-8} \approx 2^{-25}. Bei 23 Bit Mantisse codiert das niederwertigste Bit für 2^{-24}, also besteht kein Anlass zur Sorge.

avr-gcc unterstützt intern nur float (1 Sign, 23 Mant, 7 Expo). Auch Verwendung von double hilft nicht weiter, da die libgcc2 für avr-gcc nur für SFmode (float) generiert ist. Verwendung von double bringt lediglich Overhead beim Umwandeln und mehr Speicherverbrauch. Falls du höhere Genauigkeit benötigst, dann Benötigst du überhaupt höhere Genauigkeit? Oder ist es ein ästhetisches Problem?
eigene Bibliothek implementieren: Unterstützung für
-- double (1 Sign, 56 Mant, 11 Expo) oder
-- long double (1 Sign, 64 Mant, 15 Expo)
-- floats nach eingenem Gusto
-- Fixpunkt-Arithmetik nach eigenem Gusto
-- exakte Arithmetik nach eigenem Gusto (ganze Zahlen, rationale Zahlen oder Erweiterungskörper von Q)
eigene Version von avr-gcc generieren, die double bzw long double unterstützt. Die Quellen hast du ;-)
Dazu müssen Anpassungen im GCC-Backend für avr gemacht werden.
entsprechende Bibliothek besorgen (kaufen / in Auftrag geben), CA-System (Computer-Algebra)


sprintf() ist ANSI-C, die %-Modifier müssen zu den Typen passen. Wenn du mit % einen 8-Byte-Wert angibst, lieferst aber nur 4 Bytes ab, dann sei froh, daß du einen Compilezeit-Fehler/Warnung bekommst, und nicht einen Laufzeitfehler wegen Stapel-Korruption!


Soll das etwa heissen, dass mein ATMEL zu "dumm" ist um diverse Trigonometrische funktionen GENAU auszurechnen?
Was bitte meinst du mit *GENAU*???
Ein Rechner ist bestenfalls so schlau wie das Programm, das auf ihm läuft O:)

Wie sieht eine genaue Darstellung von sin(1) deiner Meinung nach aus?

Bist du dir klar über die mathematischen/algorithmischen Grundlagen von dem, was du tun willst?

PicNick
23.11.2005, 10:02
1. Soll das etwa heissen, dass mein ATMEL zu "dumm" ist um diverse Trigonometrische funktionen GENAU auszurechnen?

Wie groß ist den PI genau ?

Manf
23.11.2005, 10:04
Wie groß ist den PI genau ?
Naja, so ungefähr:
akustische Darbietung der 100 Nachkommastellen der Zahl Pi!
http://www.aip.de/~wasi/PI/AUDIO/pi100.ram

SprinterSB
23.11.2005, 10:52
Wie groß ist den PI genau ?

Warum solche Umstände?

PI ist 3,2 (http://www.zeit.de/stimmts/1997/1997_28_stimmts).

PicNick
23.11.2005, 11:15
@Sprinter:
Räum den Link lieber weg, bevor das irgendein EU Abgeordneter sieht und auf blöde Gedanken kommt.

stochri
23.11.2005, 21:12
PI ist 3,2.

echt? Ich hätte gedacht eher 3,1 O:)

izaseba
24.11.2005, 00:10
Müsste man mal probieren, ob der gcc diesen verwendet, und ob man dazu die richtige C-Formel zusammenbringt.


Hallo Linux_80,
sollte Dich(Euch) das wirklich interessieren, ich habe es gerade getestet,
ja gcc-avr verwedet MUL zumindest bei dem Mega8.

Gruß Sebastian

surfer
24.11.2005, 07:44
So... Ich sehe, dass ihr euch mächtig auskennt mit diesen Systemen!
Leider eher nichts für mich, aber ich habe eine andere Lösung gefunden:

Ich wandle die GPS-Weltkoordinaten (WGS84) in das Schweizerische Metersystem um (CH1903), womit es dann keine Probleme mit ausrechnungen etc. gibt, da alle Zahlen ins float "hinenpassen"

Diskutiert ruhig noch weiter ;-)

Klaus_0168
24.11.2005, 14:16
Hi surfer,

was hat das schweizer Metersystem ( http://www.wamister.ch/arbeitsbl/Allgemein/SI-Einheiten_CH.pdf ) mit der Problemlösung zu tun ??

Das peil ich jetzt nicht.

Grüße Klaus

surfer
24.11.2005, 18:04
Das CH1903 gibt die Koordinaten in Metern an. Y- und X-Distanz zu Bern (Hauptstadt).
Siehe hier:
http://www.swisstopo.ch/pub/down/basics/geo/system/ch1903_wgs84_de.pdf

MfG

pc-gott70
24.11.2005, 18:29
Hi surfer,
sorry dass ich jetzt mal so dumm frage - - aber was genau willst Du eigentlich machen ??
Ich sehe hier nämlich nur das Problem eines systematischen Fehlers bei Anwendung einer Floatzahl. Dieser ist meines Erachtens mit einen Wandel von WGS84 nach CH1903 nicht lösbar.
Gruß David

surfer
25.11.2005, 08:55
Also... Mein eigentliches Ziel ist die Entfernungsberechnung mit einem GPS-Empfänger -- GPS-Vermessung...
Dieses liefert mir einen String mit den Koordinaten (Längen- und Breitengrad). Wenn ich jetzt direkt mit diesen Koordinaten die Distanz (zwischen zwei Punkten) ausrechnen möchte, müsste der uC nach folgender Formel rechnen:

als allererstes muss man die koordinaten in altgrad umrechnen, was z.B. folgendes wäre: 47° 8' 12.4565'' --in Altgrad--> 47.136793472222222°

danach die eigentliche Formel... :

entfernung=arccos(sin(breit1)*sin(breit2)*cos(brei t1)*cos(breit2)*cos(laeng2-laeng1))*(40030/3600)

nun gibt es da eben diese float-kommafehler und das resultat verfälscht sich um bis zu 100-500m ...

ich kann jedoch ins CH1903 umrechnen, ohne die float-grenzen gross auszureizen... jaja, vielleicht ist es nicht 100% aber das 0.00001m macht mir jetzt auch nichts mehr...
also eben, ich kann ohne fehler ins schweizerische System umrechnen...
das gibt mir dann z.B.:
Y1=700000m
X1=200000m
Y2=700004m
X2=200003m

nun d1=x2-x1=3
und d2=y2-y1=4

nach pythagoras macht das dann eine gesamtlänge von 5m ....
that's it und es funktioniert...

MfG Surfer

Klaus_0168
25.11.2005, 11:06
Hi all,


Das CH1903 gibt die Koordinaten in Metern an. Y- und X-
Distanz zu Bern (Hauptstadt).
mercy vielmals.

Hast Du schon mal daran gedacht die schweizer Formel umzurechnen und Deinen Heimatort als Zentrum zu verwenden ? Das sollte die Genauigkeit nochmal um einiges erhöhen.

Grüeß Klaus

surfer
25.11.2005, 14:24
Hallo Klaus

Wäre eine tolle Idee, jedoch für meine Zwecke nicht nötig... (ist genau genug...)

MfG