Sers Ng,
mein ATMega32 ist zu schwach im Kopfrechnen ...
Ich lese Daten aus einem GPS-RX aus und versuche die Entfernung
zwischen zwei punkten zu brechnen (der 1. Punkt wurde vorher
gespeichert), wenn ich den code im MS DevStudio laufen lasse, funzt der
Code, auf dem AVR bekomme ich immer 3,11 KM (am anfang) raus ...
Wenn die Entfernung größer wird, dann springt er auf 6 oder 9 KM, was
ich merkwürdig finde ...
Rechne ich mit dem Taschenrechner nach, dann bekomme ich bis zu 1m oder
2m ein "korrektes" ergebnis ...
Vieleicht hat ja jmd eine Idee...
Vielen Dank im Vorraus,
Christian
#define PI3 57.295779513082320876798154814105
//variables
///////////
double dWidth1 = atol(szNorth);
double dLength1 = atol(szEast);
double dWidth2 = atol(szNorthHome);
double dLength2 = atol(szEastHome);
double dResult = 0.0;
double t1 = 0.0;
double t2 = 0.0;
double t3 = 0.0;
if(strlen(szNorthHome) > 0)
{
strnset(szDST, 0, 10);
t1 = sin(dWidth1 / PI3) * sin(dWidth2 / PI3);
t2 = cos(dWidth1 / PI3) * cos(dWidth2 / PI3);
t3 = t1 + t2 * cos((dLength1 - dLength2) / PI3);
if(t3 < 1)
{
dResult = (6371.0 * acos(t3));
}
else
{
dResult = 0;
};
};
dtostrf(dResult, 5, 4, (char*)szDST);
}
else
{
dtostrf(0, 5, 4, (char*)szDST);
};
Enthalten szNorth, szEast, szNorthHome und szEastHome denn nur Integer?
Denn atol konvertiert ja nur Stringdarstellungen von Integern. Sprich
atol("52.1") ergibt 52, auch wenn Du's einem Double zuweist.
Evtl. solltest Du Dir mal atof (und das restliche User-Manual zur
avr-libc) angucken.
Hallo Christian,
atof ist in meiner libc noch nicht implementiert ...
Also suche ich zur Zeit eine andere Lösung, wobei atol als
long atol(const char *__nptr)
definiert ist, jetzt müsste ich wissen wie sich long verhält ...
Lg
Christian
könnte auch daran liegen, dass der Compiler gar kein double unterstützt,
meckert zwar nicht, führt Berechnungen aber trotzdem nur mit
float-Genauigkeit (32bit) aus. Das kann u.U. zu sehr wunderlichen
Erscheinungen führen...
Hallo Rolf,
ich meine mit wieveil nachkommastellen sich long verhält, da ja
nachkommastellen berechnet werden ...
Insgesamt habe ich 6 Nachkommastellen, die es zu berechnen gilt ...
Lg
Christian
Hi
long ist ein doppelter int, double ist ein doppelter float. Du kannst
den String-zu-Zahl-Algorithmus auch selbst implementieren, das ist
nicht wirklich schwer: (die Performance mal ausser Acht gelassen)
bVorDemKomma = Ja
nZiffer = 0
nDurchgang = 0
Resultat = 0
Für jeden Buchstaben x
nDurchgang++
Ist x = . oder , ?
bVorDemKomma = Nein
Ist '0' <= x <= '9'
nZiffer = ASCII_Code(x) - ASCII_Code(0)
Ist bVorDemKomma ?
Resultat = Resultat * 10 + nZiffer
Sonst
Resultat = Resultat + nZiffer 10 nDurchgang
Sonst
Abbruch (Keine Zahl)
FG & HTH
Tom
Hab hier die atoff() fkt
also mit MS-Dev gehts beim avr muss man vielleicht anpassungen
vornehmen (pointer und so)
ist alles vom nc30 M16c compiler
Gruß
Jochen
1
// for.cpp : Definiert den Einstiegspunkt für die Konsolenanwendung.
ach du bist übrigens schon der zweite der probleme hat des ein avr
falsch rechnet
hier http://www.mikrocontroller.net/forum/read-1-232087.html#new
da funktionierte die sqrt() fkt nicht ganz richtig
vielleicht geben die cos() sin() .. fkt auch falsche ergebnisse zurück
Hallo Ng,
danke erst mal für die Antworten...
Das Problem scheint wohl schon an anderer Stelle bekannt zu sein:
http://lists.gnu.org/archive/html/avr-gcc-list/2002-10/msg00085.html
Mist, Ich werde die Tage mal versuchen die funktionen aus der glibc zu
fischen und einzubauen ...
Falls das schon jmnd gemacht hat oder eine andere Lösung hat...
Lg
Christian
dein problem ist weniger die fehlerhafte acos(x) funktion, auch wenn
diese einen zusätzlichen fehler verursachen könnte. das post ist von
2002, der fehler sollte also schon längst gefixt sein.
atol( x ) bricht dir die füße. long hat keine nachkommastellen, es ist
ein ganzzahl datentyp. die funktion atol( x ) berücksichtigt keine
stellen hinter dem komma!
das wurde aber alles hier bereits mehrfach gedsagt! du scheinst in
dieser beziehung lernresistent zu sein.
@Tenner,
ja, ich habe es wohl schon lang begriffen und auf das letzte WinAVR
upgedated, dort ist atof() auch implementiert, mein Problem bleibt
trotzdem bestehen ...
Versuch mal folgendes und staune:
[C]
char szSomeThing[17];
strnset(szSomeThing, 0, 17); //strnset selbst implementiert
double dStaune = atof("12.3456789\0");
dtostrf(dStaune, 16, 10, (char*)szSomeThing);
und auf einem LCD ausgeben:
12.3456788063
6 setzen...
Nächstes Beispiel:
double d = 0;
for(int n = 0; n <= 100; ++n) d += 0.0000001;
Auf dem LCD: 0.0000101 (stimmt)
Also ist die atof() Funktion für die Wurst...
Nun bin ich gerade dabei die atof() Funktion selbst zu schreiben.
Ich hoffe das es taugt, werde da aber gleich mehr wissen ...
Lg
Christian
Hallo NG,
tja, führt auch nicht zum Erfolg ...
Es kann jetzt nur noch an sin() / cos() und acos() liegen ...
Ich werde da später mal was versuchen - gute Nacht ...
Lg
Christian
mhhhhhh
ich hab doch schon ne atof fkt oben fertig reingestellt (Vom nc30
compiler für M16c) und läuft (selbst getestet) mit MS Studio C
ich frag mich nur warum sieht/ließt das keiner?????
wenn andere fkt gefragt sind kann ich ja mal den ganzen source von dem
M16c libs schicken
Hallo Jochen,
Du hast natürlich recht, da ich aber einen Fehler suche, wo ich nicht
weiß, wo ich beginnen soll, sind fertige Sachen vileicht eine neue
Fehlerquelle...
Mal davon ab, stehen mir auf dem ATMega32 nur noch 1K zur Verfügung
...
Aber ich währe an der Implementation der sin() cos() und acos()
Funktion interessiert ...
Bis jetzt habe ich das ganze immer im MS Dev Studio testen können, wo
es läuft, es kann jetzt nur noch an sin(), cos() und acos() liegen -
wenn der Compiler in der Lage ist +/-* zu rechnen ...
Vieleicht liegt es auch an den Nachkommastellen, das er bei
Veränderungen in der 5 oder 6 Stelle nicht mitkommt ...
Ich habe mal der MS DevStudio Prj angehängt, es ist gleich wie im
AVR und die Koordinaten sind fest (Österreich / Klagenfurt), im
DevStudio kommen 0.7xx raus der AVR sagt 0.000....
Ich weiß da nicht mehr weiter ...
Ich hoffe das es bald eine Lösung gibt, am Dienstag ist Clubabend und
das Teil soll ja ein wenig mehr können als den QRA-Locator
anzuzeigen....
55 es 73 de Christian OE8CWQ
BTW: Wer mag, kann sich das auch direkt bei mir mal im Shack ansehen
einfach mal auf 145.7875 MHz (-DUP / Tone) durchrufen bin ab 16.00 Uhr
QRV ...
Aller Komik zum Trotz tut's mir doch weh, mit anzusehen, wie jemand
sein Brett vorm Kopf für die Welt hält. Also noch ein Versuch:
Was beim PC funktioniert, muss beim Controller noch lange nicht
funktionieren. Erst recht nicht, wenn dessen Compiler nicht
ANSI-konform ist.
float.h vom PC:
FLT_DIG = 6
DBL_DIG = 15
LDBL_DIG = 18
float.h von WinAVR:
FLT_DIG = 6
DBL_DIG = 6 /* ANSI: >= 10 */
LDBL_DIG = 6
Im obigen Beispiel:
atof("12.3456789\0");
12.3456788063
ist das Ergebnis sogar auf 7 Stellen genau. Besser geht's nicht.
Hallo NG,
so, danke an AK für den Hinweis...
Aber woher hast Du diese Werte ?
FLT_DIG = 6
DBL_DIG = 6 /* ANSI: >= 10 */
LDBL_DIG = 6
Bei mir steht dort:
FLT_DIG _FLT_DIG_
Wobei ich _FLT_DIG_ nirgens finden kann ...
Auch wenn ich diesen Wert erhöhe, so hat das keine Auswirkung, solange
nicht die ganze lib neu kompiliert wird ...
Hat das sich schon mal jemand mit befasst und kann das mal versuchen ?
BTW: Aller Komik zum Trotz tut's mir doch weh, mit anzusehen, wie
jemand sein Brett vorm Kopf für die Welt hält.
--> Ja, da hast Du recht, mit Deinem voherigen Post konnte hier wohl
niemand was anfangen, sonst hätte es ja auch jemand anderes schon
getan.
Ich schreibe in ein Forum, weil ich nicht weiter komme und weil ich
Hilfe benötige - Ich kann halt nicht alles wissen, deshalb sind
Hinweise wie:
if (sizeof(double) > sizeof(float))
printf("das ist garantiert kein WinAVR\n");
oder der Hinweis "Satire live." über...
Wenn Du magst, dann bin ich gerne bereit, gemeinsam mit Dir oder allen
anderen eine Lösung für dieses Problem zu finden und der Allgemeinheit
zur Verfügung zu stellen...
Das ist der Sinn dieses Forums und damit kommen wir hier weiter !
Lg
Christian
chirstian scrieb:
"...und auf einem LCD ausgeben:
12.3456788063
6 setzen..."
nix für ungut, aber ich denke du solltest dich mal mit einen guten
c-buch zusammensetzen (K&R) und dir das kapitel über datentypen und
casting duchlesen. dann die docu zum winavr zur hand nehmen und schauen
wie welche datentypen implementiert sind und welchen zahlenraum sie
umfassen.
wenn du dann deinen code entsprechend überarbeitet hast und es immer
noch zu signifikanten fehlern kommt, können wir noch einmal über fehler
in der implementierung von sin(x) cos(x) ect. reden.
"Auch wenn ich diesen Wert erhöhe"
Weil der vom Compiler festgelegt ist. Daran gibt's nichts zu ändern,
das verwendete Fliesskommaformat hat nun einmal nicht mehr Stellen zu
bieten. Für mehr als 6 Dezimalstellen musst Du nicht nur die Lib
ändern, sondern auch den Compiler (gcc-*\gcc\config\avr\avr.h,
#define DOUBLE_TYPE_SIZE 32).
Ich ging übrigens davon aus, dass jemand der eben mal atof oder acos
neu schreibt, dem Statement
if (sizeof(double) > sizeof(float))
printf("das ist garantiert kein WinAVR\n");
entnehmen kann, dass in WinAVR "double" nicht genauer ist als
"float". Anders als beim PC. Sorry für die Fehleinschätzung.
Abhilfe: (a) Compiler verwenden, der ein 64-bit Fliesskommaformat
unterstützt. (b) C++ verwenden und die Arithmetik darin als eigenen
Datentyp unter Verzicht auf float/double komplett selbst realisieren.
@Stupsi:
Wenn du dir den ganzen Thread durchliest, wirst du feststellen, dass die
Antwort bereits mehrmals gepostet wurde. Hier nochmal:
Die AVR libc rechnet mit Fliesskommazahlen bis 32 Bit und nicht mehr.
Basta.
Um genauere Ergebnisse zu erhalten musst du entweder mit genügend
grossen Festkommawerten arbeiten (Ganzzahltypen verwenden und das Komma
bei der Ausgabe reinschummeln), oder aber selbst Funktionen für
Berechnungen mit höherer Genauigkeit erstellen. Ich empfehle Ersteres,
besonders für ein GPS oder so. Nimm deine gröbste Auflösung mit der du
noch klarkommst und rechne aus, wie gross deine Datentypen dann sein
müssen um den ganzen Bereich abzudecken. Wenn's mit 32 Bit geht hast du
Glück...
Auf
http://williams.best.vwh.net/avform.htm#Dist
findet sich eine Formel, mit der Distanzen ohne den bei mir und bei
Christian aufgetretenen Fehler, der durch die Ungenauigkeit von
Fliesskommazahlen des Controllers entsteht, berechnet werden können.
Damit hat sich mein Problem gelöst.