Division in Festkommaarithmetik auf M0

Gast #2620377
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
Gast #2620476
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
Gast #2620545
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!
Gast #2620555
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.
Angehängte Dateien:
Gast #2620683
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?
#2620735
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.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren