Forum: Compiler & IDEs Konvertierung Kommazahl->Fixed-Point-Format durch Precompiler ungenau!?


von krischi (Gast)


Lesenswert?

Hallo,

für mein Projekt benutze ich eine kleine selbst geschriebene Fixed-Point 
Bibliothek um Berechnungen im Format s15.16 durchführen zu können. 
Bisher dachte ich eigentlich, dass diese gut funktionieren würde, doch 
heute ist mir per Zufall aufgefallen, dass der Precompiler vorgegebene 
Werte teilweise recht ungenau konvertiert. Zur Konvertierung nutze 
folgende Typendefinition und ein entsprechendes Makro:
1
typedef s15_16_t       int32_t
2
3
#define floatToFix(f)  ((s15_16_t)( (f) * (1<<16) ))

Wenn ich nun z.B. 693,0983 konvertieren möchte und das durch den 
AVRStudio Simulator jage, liefert mir dieser als Ergebnis 0x02B5192C 
bzw. dezimal 45422892. Wenn ich das nun aber per Hand ausrechne bekomme 
ich 693,0983 * 65536 = 45422890,1888. Nach Abschneiden der 
Nachkommastellen ergibt das allerdings eine Differenz von 2! Obwohl es 
mir logisch erscheinen würde, dass der Precompiler ebenfalls die Stellen 
abschneidet, gebe es selbst im Fall dass er aufrundet immer noch einen 
Unterschied von 1!

Wie ist dieses Verhalten zu erklären? Prinzipiell sollte eine einfache 
Multiplikation von zwei solch gutmütigen Zahlen (beide in etwa in der 
gleichen Größenordnung) doch nicht derartig ungenau sein! Kann jemand 
dieses Verhalten reproduzieren oder hab ich vielleicht irgendwo anders 
einen Fehler?

Achja, das ganze habe ich mit dem neuesten WinAVR-20090313 kompiliert.

Vielen Dank im voraus!

Gruß, krischi

von Peter D. (peda)


Lesenswert?

Der AVR-GCC hat nur das einfache float Format und kein double.
D.h. die Mantisse hat nur eine Genauigkeit von 23 Bit.

Deine Zahl ist aber deutlich größer als 23 Bit und daher muß der Fehler 
>1 sein.


Peter

von (prx) A. K. (prx)


Lesenswert?

krischi schrieb:

> Wie ist dieses Verhalten zu erklären? Prinzipiell sollte eine einfache
> Multiplikation von zwei solch gutmütigen Zahlen (beide in etwa in der
> gleichen Größenordnung) doch nicht derartig ungenau sein!

Nebenbei: Bei Multiplikation und Division von Fliesskommazahlen spielt 
es überhaupt keine Rolle, ob die Operanden in der gleichen 
Grössenordnung liegen oder extrem auseinander. Das ist nur bei Addition 
und Subtraktion relevant.

von krischi (Gast)


Lesenswert?

Ah, vielen Dank! Das erklärt das natürlich. In die Richtung habe ich 
schon gedacht, aber wie man sieht habe ich von float nicht wirklich viel 
Ahnung. Das werde ich gleich mal als Anlass nehmen, um mich etwas 
intensiver mit der Thematik zu beschäftigen.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Es gibt übrigens keinen `precompiler'.

Es gibt nur einen Präprozessor (bzw. mittlerweile `preprocessing'
genannt, da es selbst beim GCC kein separat gestarteter Prozess
mehr ist), aber der macht nur dumme Makroersetzung.  Die Berechnung
von zur Compilezeit konstanten Ausdrücken obliegt dem Compiler
selbst.

von Ollz (Gast)


Lesenswert?

> Die Berechnung von zur Compilezeit konstanten Ausdrücken obliegt dem
> Compiler selbst.

Mit dem kleinen Sonderfall, dass der GCC Preprozessor konstante 
Integer-Ausdrücke in Bedingungen (#if) ebenfalls ausrechnet um die 
Bedingung zu prüfen. Dabei rechnet er mit dem grössten Integer-Typ den 
er hat.

Verwendet man den gleichen Ausdruck im eigentlichen Code, kann nach 
Expansion (durch den Preprozessor) und dann Berechnung durch den 
Compiler bei dieser Berechnung was anderes rauskommen, als das, was der 
Preprozessor sich in einer Bedingung ausgerechnet hat. Sehr lustig :-(

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.