Hallo,
Folgender Code Schnipsel produziert unterschiedliche Zahlen. Auf dem Pc
mit GCC korrekt und auf dem AVR mit AVG-GCC falsch. Aber wieso?
1
unsignedcharrfreq[9];
2
unsignedchari;
3
4
for(i=0;i<9;i++)rfreq[i]=0;
5
6
rfreq[4]=2;
7
rfreq[3]=168;
8
rfreq[2]=108;
9
rfreq[1]=224;
10
rfreq[0]=36;
11
12
13
unsignedlonglongtmp;
14
doubledbl=0;
15
16
void*vptr;
17
vptr=&rfreq[0];
18
19
tmp=*(unsignedlonglong*)vptr;
20
dbl+=tmp;
21
dbl/=(unsignedlonglong)268435456;
Ist jetzt zwar ziemlich gehackt aber sollte doch laufen?!?
Richtiges Ergebnis wäre ungefähr 42,52658094465732574463
Auf dem Pc schau ich mir das ganze mit : "printf("Zahl: %f\n",dbl);" an
und auf dem Controller mit: "lcd_puts( dtostre(dbl,conv_str,31,0x04)
);". Die Variable conv_str ist 100 Byte lang, nur zur Sicherheit...
Ich verstehs nicht. Bitte Hilfe :)
Grüße Daniel
Daniel R. schrieb:
> Auf dem Pc mit GCC korrekt und auf dem AVR mit AVG-GCC falsch.
g457 schrieb:
> Ohne zu wissen auf welchen Architekturen Du das getestet hast und ohne> die Zeigerarithmetik nachgeprüft zu haben: Ich tippe auf Endianness.> Ist jetzt zwar ziemlich gehackt aber sollte doch laufen?!?
Ein Grund könnte sein, daß double auf dem AVR 32 Bit breit ist.
Ich verstehe es auch nicht.
Wieso ist z.B. rfreq 9 Elemente groß?
Ansonsten sehe ich das auch so, daß du von 8-Byte-double ausgehst, was
bei AVR falsch ist.
Wer nicht weiß, was er macht und wie die interne Darstellung aussieht,
sollte vielleicht etwas defensiver programmieren?
Daniel R. schrieb:
> Auf dem Pc schau ich mir das ganze mit : "printf("Zahl: %f\n",dbl);" an> und auf dem Controller mit: "lcd_puts( dtostre(dbl,conv_str,31,0x04)> );".
Das ist zwar nett, aber höchst wahrscheinlich sinnlos um dem Problem auf
die Spur zu kommen.
Du willst dein Byte-Array als unsigned long long einsetzen. Also
solltest du dir als Allererstes ansehen, ob die Interpretation der Bytes
als unsigned long long auf dem AVR mit der auf dem PC übereinstimmt.
Wenn die schon nicht übereinstimmt (Stichworte wurde ja schon genannt:
Endianess, unterschiedliche Datentyplängen), darfst du dich nicht
wundern, wenn danach nichts mehr stimmt.
> Ich verstehs nicht. Bitte Hilfe :)
Binäre Übertragung von Zahlen kann tricky sein. Will man diesen
Problemen aus dem Weg gehen, dann einigt man sich auf den absolut
kleinsten Nenner: Zahlen werden in textform übertragen. Neben Problem
mit der Endianess und unterschiedlichen Darstellungen (bei float/double)
hat das dann auch noch den Nebeneffekt, das Protokollsynchronisierung
viel einfacher ist.
Hallo,
danke für die Tips.
Hintergrund des Codes ist, dass ich mit einem AVR die Register eines
SI570 über TWI auslese und jetzt die Berechnung der neuen Registerwerte
vornehmen will, dazu brauche ich mindestens 38 Bit Gnauigkeit.
Das double nur 4 Byte lang ist wusste ich nicht, finde ich auch seltsam.
Wie lang ist denn dann ein Float? Wo stehen denn die Datentypen in der
avr-libc? Gibt es im c99 Mode denn dann 8 Byte long double?
Mit der Endianess war ich mir eigentlich auch sicher, dass die bei
beiden Plattformen übereinstimmt. Einmal mein Notebook mit Linux x86 gcc
und beim Atmega168 mit avr-gcc.
Grüße Daniel
Daniel R. schrieb:
> Das double nur 4 Byte lang ist wusste ich nicht, finde ich auch seltsam.
Ist nicht konform mit dem Standard, wurde aber der Einfachheit halber so
implementiert. Es gibt beim avr-gcc keine 64-Bit Fliesskommarechnung.
Wenn dir also 64-Bit Integers nicht ausreichen...
>Es gibt beim avr-gcc keine 64-Bit Fliesskommarechnung.
Hm schade, dann muss ich wohl doch mehr programmieren als ich vorhatte
:)
Nun gut.
Danke an alle.
Viele Grüße
Daniel
Daniel R. schrieb:
> Hintergrund des Codes ist, dass ich mit einem AVR die Register eines> SI570 über TWI auslese und jetzt die Berechnung der neuen Registerwerte> vornehmen will, dazu brauche ich mindestens 38 Bit Gnauigkeit.
Lass mal die Kirche im Dorf. Mit einer 32-bit-Gleitkommazahl erreichst
du eine Genauigkeit von 6...7 Dezimalstellen, also besser als 1E-6.
Der Si570 hat eine Genauigkeit von 1.5E-6, und das bereits ohne
Berücksichtigung von Temperatureinflüssen.
Hallo,
ja Festkommaarithmetik steht jetzt auf dem Programm, ist wahrscheinlich
eh schneller und evtl. je nach Aufwand genauer als mit 32 Bit Fließkomma
zu rechnen.
@Jörg Wunsch
Du sprichst die 1.5 ppm Initial Accuracy an die im Datenblatt angegeben
ist, richtig?
Der Si570 wird mit Heizung in Metallgehäuse betrieben und mit einem
Frequenznormal Kalibriert, das sollte dann besser als 1.5 ppm werden,
denke ich mal wobei 1.5 ppm schon nicht schlecht ist :)
Im Datenblatt steht das man mit 38 Bit rechnen soll...
Grüße Daniel
Daniel R. schrieb:
> ja Festkommaarithmetik steht jetzt auf dem Programm, ist wahrscheinlich> eh schneller
Ich glaube, das ist ein Trugschluss.
> und evtl. je nach Aufwand genauer als mit 32 Bit Fließkomma> zu rechnen.
Ob sie genauer wird, hängt u. a. davon mit ab, ob du mehrere Dekaden
überstreichen musst oder nur einen engen Bereich. Ein Vorteil der
Gleitkommazahlen ist halt, ungefähr die gleiche Genauigkeit über
viele Zehnerpotenzen Gesamtgröße zu bieten.
> Du sprichst die 1.5 ppm Initial Accuracy an die im Datenblatt angegeben> ist, richtig?
Ja.
> Der Si570 wird mit Heizung in Metallgehäuse betrieben und mit einem> Frequenznormal Kalibriert, das sollte dann besser als 1.5 ppm werden,> denke ich mal wobei 1.5 ppm schon nicht schlecht ist :)
Naja, die Langzeitstabilität war ja auch noch einmal eine Größen-
ordnung schlechter angegeben, und Temperatureinflüsse hatte ich
sowieso nicht berücksichtigt.