Datentypkonvertierung uint16_t zu double

Gast #5069649
Lesenswert?

Moin,
bisher habe ich es immer vermieden mit float und double zu arbeiten, 
weil es mir unheimlich ist. Da ich nun aber auch sin + cos verwenden 
muss, komme ich nicht drumherum.

Nun habe ich auch schon das erste Problem. Ich habe drei Werte in 
uint16_t und ich benötige jeweils drei double Werte im Bereich von 0..1, 
die das Verhältnis wiederspiegeln. Also habe ich es wie folgt versucht 
zu lösen. (Vereinfachtes Beispiel)

Prozessor: ARM Cortex M3 (STM32F103)
Compiler: ARM Yagarto
1
uint16_t a = 1054;
2
uint16_t b = 84;
3
uint16_t c = 1403;
4

5
double all = a + b + c;
6
double a_ = (double)a / all;
7
double b_ = (double)b / all;
8
double c_ = (double)c / all;

Hier ist mir aufgefallen, dass der b Anteil viel zu groß erscheint. Also 
habe ich mir mal die konvertierten Zahlen ausgegeben:
1
uint16_t a = 1054;  // Nach (double)a steht hier 2048 drin
2
uint16_t b = 84;    // Nach (double)b steht hier 855 drin
3
uint16_t c = 1403;  // Nach (double)c steht hier 2048 drin

Kann das sein?! - So schlecht kann man doch gar nicht auf / abrunden bei 
der Typkonvertierung.

Was mache ich falsch?

Vielen Dank für eure Unterstützung.
#5069661
Lesenswert?

Fabian schrieb:
> uint16_t a = 1054;  // Nach (double)a steht hier 2048 drin

Eventuell kommt auch nur der Debugger beim Anzeigen durcheinander. Der 
Compiler arbeitet ja intern mit den (32-bittigen) Registern, und für 
double müsste man gleich 2 zusamman auswerten.

Hier würde ich mir den generierten Assembler Code zusammen mit den 
Regsiter Inhalten genauer anschauen.

Vorsicht: Als ich das letzte Mal yagarto benutzt habe, war (*)printf für 
float Formate (%f etc.) kaputt. Zur Anzeige habe ich die Werte in 
Ganzzahlen zurück gewandelt. Die Anzeige der Variablen im Debugger 
sollte das aber nicht betreffen.
Gast #5069667
Lesenswert?

Fabian schrieb:
> uint16_t und ich benötige jeweils drei double Werte im Bereich von 0..1,
> die das Verhältnis wiederspiegeln.

Was für einen Compiler benutzt du?

Der Datentyp double ist bei vielen µC-Compilern nur Augenwischerei und 
wird tatsächlich als float umgesetzt, i.e. mit 7-8 signifikanten Stellen 
und nicht mit 15-16, wie man es vielleicht erwarten könnte.
Gast #5069673
Lesenswert?

Oh mann, da war ich völlig auf der falschen Spur. Das Problem lag ganz 
wo anders. Hinter a, b und c befinden sich in Wirklichkeit Pointer auf 
Werte und dieser Speicherbereich war nicht mehr gültig, da er im Stack 
lag. Nun funktioniert alles wie erwartet!

Vielen Dank euch, ich gehe jetzt mit gesenktem Kopf...
Gast #5069809
Lesenswert?

.... Aber Vorsicht bei deinem printf Format!

%u erwartet unsigned int, du hast uint_16
%f erwartet float, du hast double.

Möglicherweise funktioniert das implementierungsbedingt bei dir.
Du solltest die Variablen entsprechend den Vorgaben der Formatbezeichner 
casten.

Grüße, Adib.
#5069822
Lesenswert?

Adib schrieb:
> Uhh, hab noch mal nachgeschaut. Printf kennt kein float.
> Also %f ist double.

So ist es, float immer schön nach double casten und char nach int.
Beim Keil C51 gibt es zwar einen Formatbezeichner für char-Zahlen, aber 
wenn man portabel sein will, besser nicht benutzen.
Die Ausgaben sind ja in der Regel für den langsamen Menschen, also muß 
man da nicht optimieren.
#5069832
Lesenswert?

Adib schrieb:
> %f erwartet float, du hast double.

Wenn man keine Ahngung hat ... </Nuhrzitat>

Das %f würde auch mit double funktionieren - wenn man eine andere 
C-Library als Newlib verwendet. Die newlib braucht dafür leider relativ 
viel Speicherplatz auf dem Heap über malloc(), den man auf ARM Cortex-M 
eher selten hat. Aber es gäbe alternative sprintf() Implementationen.

Und %u nimmt auch uint16_t an...
Gast #5070511
Lesenswert?

Nennt sich glaube ich Optimierung. Nach der Umwandlung in 
Flieskommazahlen kräht kein Hahn mehr nach den Integervariablen. Daher 
wird deren Speicherplatz für andere schöne Werte benutzt. Der Debugger 
gibt Dir halt weiterhin den Wert aus der Speicherzelle aus, wo die 
Integervariable mal stand, als sie noch gebraucht wurde.
Es gibt zwar auch Versuche, dem Debugger Tips zu geben, ob eine Variable 
existiert. Die schießen aber unter Umständen über das Ziel hinaus, so 
dass Du einen Variableninhalt nicht angezeigt bekommst, obwohl die 
Variable noch existiert.

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