Forum: Compiler & IDEs Division in Festkommaarithmetik auf M0


von Caradhras (Gast)


Lesenswert?

Moin,

ich versuche auf einem Cortex M0 eine Division mit Festkommaartihmetik 
hinzubekommen. Aber irgendwie will das nicht.

Der Code stammt aus einem Programmierbeispiel, den ich etwas abgewandelt 
habe, liefert aber nicht das richtige Ergebnis.
1
typedef int32_t fx_t;
2
3
#define FX_FRAC 12        // define position of decimal point
4
// explanation: FX_FRAC = 12 ==> 20 Bit for Integer-Value, 12 for fractional value
5
6
#define fx_float(a) (a / (float)(1LL<<FX_FRAC))
7
#define fx_make(a)  ((fx_t)(a * (1LL<<FX_FRAC)))
8
#define fx_add(a,b) (a + b)
9
#define fx_sub(a,b) (a - b)
10
#define fx_mul(a,b) ((fx_t)(((int64_t)a * b) >> FX_FRAC))
11
#define fx_div(a,b) ((fx_t)(((int64_t)a << FX_FRAC) / b))
12
13
uint32_t zahl = 934;
14
zahl = fx_make(zahl);
15
uint32_t teiler = 33;
16
teiler = fx_make(teiler);
17
uint32_t ergebnis = 0;
18
ergebnis = fx_div(zahl, teiler);

Der Integerteil ist ok und gibt korrekt 28 aus, aber der Nachkommateil 
stimmt zumindest mit meinem Taschenrechner nicht überein... ;-)

Weiß jemand, was hier nicht stimmt? ich hab schon allerhand Tutorials 
zum Thema FPA gelesen, aber irgendwie fehlt noch der Sprung in die 
Praxis.

Besten Dank
Caradhras

von Klaus W. (mfgkw)


Lesenswert?

Caradhras schrieb:
> Aber irgendwie will das nicht.

Ach, sooo genau wollte das gar keiner wissen :-)

Was erwartest und was bekommst du stattdessen?

von Krapao (Gast)


Lesenswert?

zahl, teiler und ergebnis sollten vom Typ fx_t sein.
Hast du daran gedacht die Maske in fx_get_fraction(a) auf FX_FRAC 
anzupassen?

Der Nachkommateil ist umso "schlechter", je weniger Bit du dem 
Nachkommawert über FX_FRAC spendierst.

Bei 12 Bit komme ich mit der Originalsource (lediglich die Warnungen 
korrigiert) auf:
zahl=934.000000
teiler=33.000000
ergebnis=28.302979
fraction=0.302979
trunc=0.006836

Bei 16 Bit komme ich mit der Originalsource (lediglich die Warnungen 
korrigiert) auf:
zahl=934.000000
teiler=33.000000
ergebnis=28.303024
fraction=0.303024
trunc=0.000427

von Krapao (Gast)


Lesenswert?

> trunc=0.006836
> trunc=0.000427

Ist ein Fehler von mir, weil ich meinem printf %f statt %ld als 
Formatparameter gegeben hatte. Mit %ld wird korrekt 28 angezeigt.

von Caradhras (Gast)


Lesenswert?

Hoi Krapao!

Danke schon mal für deinen Beitrag, du scheinst meinen Code schon 
selbstständig erweitert zu haben. Oder ist das Teil einer 
Standardbibliothek, die ich bis jetzt noch nicht kannte? Kannst du den 
Code mal posten, mit dem du die Ausgabe erzeugt hast?

Also wenn die ersten beiden Nachkommastellen passen, dann ist schon 
alles in Ordnung. Auf meinem µC kam irgendwas mit 28.136 raus. (Per 
Debug-Wire ausgelesen)

Viele Grüße und danke!

von Krapao (Gast)


Angehängte Dateien:

Lesenswert?

Du hattest doch geschrieben, dass es ein Programmierbeispiel gibt, das 
du abgewandelt hast. Nach dem Programmierbeispiel habe ich gesucht und 
was gefunden:

http://code.google.com/p/lpc-1768-arm-synthesizer/source/browse/Synthesizer/inc/auxiliary/Q16.h?spec=svn26215a56c4b1c35757cb81205a6b0722b593a021&r=26215a56c4b1c35757cb81205a6b0722b593a021

http://forums.arm.com/index.php?/topic/14281-arm-fixed-point-vs-floating-point-cortex-m-3/

Das daraus erstellte Testprogramm steckt im Anhang. Zum Übersetzen habe 
ich tcc (http://bellard.org/tcc/) benutzt.

von Caradhras (Gast)


Lesenswert?

Hehehe,

man sieht, du bist besser bei Google als ich :D

Ich hatte nur den Foreneintrag, nicht den Google Code Eintrag! Mal 
testen...

von Caradhras (Gast)


Lesenswert?

Ich habe immer noch ein Brett vor dem Kopf, was fraction angeht.

Also wenn ich mir das Integer bzw. Binärwert anschaue, dann ist Integer 
ganz logisch 11100 => 28 zur Basis 10. Soweit richtig!

Aber der Nachkommawert entpuppt sich als 4D93 bzw. 0100110110010011 oder 
19859 zur Basis 10. Ich hätte jetzt naiv irgendwas mit einer 3 vorneweg 
erwartet. 30303 oder so.

Wo liegt mein Denkfehler?

von Klaus W. (mfgkw)


Lesenswert?

Wo ist das Problem?

934/33 gibt 28.30303...

Die 28 hast du ja schon, klar.

Nach dem Komma hast du hexadezimal 4D93.
Die 4 steht für Sechzehntel, also 4/16.
Das D ist 13 (wegen D) durch 16^2 (wegen ihrer Position), die 9 ist 
9/16^3 und die 3 ist 3/16^4.

28+4.0/16+13.0/16/16+9.0/16/16/16+3.0/16/16/16/16 sind doch etwa 
28.30302.

Was gefällt dir daran nicht?

Man könnte auch binär rechnen: 0100110110010011 ()als Ziffernfolge der 
Nachkommastellen ist 0 Halbe + 1 Viertel + 0 Achtel + 0 Sechzehntel + 1 
Zweiunddreißigstel..., aber das spare ich mir - es kommt hoffentlich 
dasselbe raus.

von Caradhras (Gast)


Lesenswert?

Au weiha,

ja das war ein großes Brett! Habe es jetzt verstanden. :D

Danke sehr!

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.