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...
> jetzt müsste ich wissen wie sich long verhält ...
Was meinst du damit? long ist halt ein Ganzzahltyp und verhält sich
auch so.
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
>atof ist in meiner libc noch nicht implementiert ...
Wie wär's mit sscanf ?
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.
|
2 | //
|
3 | |
4 | #include <iostream> |
5 | #include <tchar.h> |
6 | #include <float.h> |
7 | |
8 | |
9 | |
10 | float atoff(const char *s); |
11 | float strtof(const char *s, char * *endptr); |
12 | static int isinfinity(float d); |
13 | |
14 | typedef struct { |
15 | unsigned long sign : 1; /* */ |
16 | unsigned long exp : 8; /* (mantissa) */ |
17 | unsigned long mant : 23; /* (mantissa) */ |
18 | } SGL_FLT; |
19 | |
20 | typedef SGL_FLT * SGL_FLTP; |
21 | |
22 | #define SGL_INFEXP 0xff
|
23 | |
24 | |
25 | |
26 | |
27 | int _tmain(int argc, _TCHAR* argv[]) |
28 | {
|
29 | char ttt[]="52.4"; |
30 | float fff; |
31 | fff=atoff(ttt); |
32 | |
33 | |
34 | |
35 | return 0; |
36 | }
|
37 | |
38 | |
39 | |
40 | /*****************************************************************************
|
41 | * atoff
|
42 | * float
|
43 | * #include <stdlib.h>
|
44 | * float atoff(const char *s);
|
45 | *
|
46 | * const char *s;
|
47 | * float
|
48 | * S.Kanamori
|
49 | * K.Kato
|
50 | * 2002/12/01
|
51 | |
52 | *****************************************************************************/
|
53 | float atoff(const char *s) |
54 | {
|
55 | return strtof(s, (char * *)NULL); |
56 | }
|
57 | |
58 | |
59 | |
60 | |
61 | /*****************************************************************************
|
62 | * strtof
|
63 | * float
|
64 | * #include <stdlib.h>
|
65 | * float strtof(const char *s, char **endptr);
|
66 | *
|
67 | * const char *s;
|
68 | * char **endptr;
|
69 | * 0L :
|
70 | * float
|
71 | * S.Kanamori
|
72 | * K.Kato
|
73 | * 2002/12/01
|
74 | |
75 | *****************************************************************************/
|
76 | float strtof(const char *s, char * *endptr) |
77 | {
|
78 | float d, e; |
79 | float base; |
80 | int exp = 0; |
81 | char sign = '+'; |
82 | char esign = '+'; |
83 | char *p = (char *)s; |
84 | |
85 | d = e = 0.0F; |
86 | |
87 | if (!p) { |
88 | /* NULL 0.0 (ANSI ) */
|
89 | return 0.0F; |
90 | }
|
91 | |
92 | /* ( ) */
|
93 | for (; isspace(*p); p++); |
94 | |
95 | if ((*p == '-') || (*p == '+')) { |
96 | /* */
|
97 | sign = *p++; |
98 | }
|
99 | if (!isdigit(*p)) |
100 | goto STRTOD_END; |
101 | |
102 | /* */
|
103 | for (s = p; isdigit(*s); s++) { |
104 | /* 10 */
|
105 | d = (d * 10) + (float)(*s & 0xf); |
106 | }
|
107 | |
108 | /* */
|
109 | if (*s == '.') |
110 | s++; |
111 | |
112 | /* */
|
113 | for (base = 1.0F; isdigit(*s); s++) { |
114 | base /= 10; |
115 | e += base * (float)(*s & 0xf); |
116 | }
|
117 | /* */
|
118 | d += e; |
119 | |
120 | if (*s == 'e' || *s == 'E') { |
121 | /* d.dd..e+dd */
|
122 | s++; |
123 | if (*s == '+' || *s == '-') { |
124 | /* */
|
125 | esign = *s++; |
126 | }
|
127 | for (; isdigit(*s); s++) { |
128 | if (exp > FLT_MAX_10_EXP) |
129 | continue; |
130 | exp = exp * 10 + (int)(*s & 0xf); |
131 | }
|
132 | }
|
133 | if (d && exp) { |
134 | /* */
|
135 | if (esign == '-') { |
136 | if ((-exp) <= FLT_MIN_10_EXP) { |
137 | /* Under-flow */
|
138 | d = 0.0F; |
139 | errno = ERANGE; |
140 | goto STRTOD_END; |
141 | }
|
142 | } else { |
143 | if (exp >= FLT_MAX_10_EXP) { |
144 | /* Over-flow */
|
145 | d = FLT_MAX; |
146 | errno = ERANGE; |
147 | goto STRTOD_END; |
148 | }
|
149 | }
|
150 | |
151 | for ( ; exp; ) { |
152 | if (exp / 10) { |
153 | if (esign == '-') |
154 | d /= 10000000000.0F; |
155 | else
|
156 | d *= 10000000000.0F; |
157 | exp -= 10; |
158 | } else { |
159 | d = ((esign == '-') ? (d / 10.0F) : (d * 10.0F)); |
160 | exp--; |
161 | }
|
162 | if (isinfinity(d)) |
163 | break; |
164 | if (d == 0.0F) { |
165 | /* Under-flow */
|
166 | errno = ERANGE; |
167 | break; |
168 | }
|
169 | }
|
170 | }
|
171 | |
172 | STRTOD_END:
|
173 | if (endptr) |
174 | /* */
|
175 | *endptr = (char *)s; |
176 | if (sign == '-') |
177 | d = -(d); |
178 | if (isinfinity(d)) |
179 | errno = ERANGE; |
180 | return d; |
181 | }
|
182 | |
183 | /*****************************************************************************
|
184 | * isinfinity
|
185 | * float
|
186 | * static int isinfinity(float d);
|
187 | *
|
188 | * float d; float
|
189 | * 1 : Infinity
|
190 | * 0 : Normal
|
191 | * S.Kanamori
|
192 | * K.Kato
|
193 | * 2002/12/01
|
194 | |
195 | *****************************************************************************/
|
196 | static int isinfinity(float d) |
197 | {
|
198 | SGL_FLTP dp; |
199 | |
200 | dp = (SGL_FLTP)&d; |
201 | if (dp->exp == SGL_INFEXP) { |
202 | /* Infinity */
|
203 | return 1; |
204 | }
|
205 | return 0; |
206 | }
|
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
@Christian: long hat KEINE Nachkommastellen, d.h. atol liefert auch keine Zurück. Was für einen Compiler bzw. was für eine libc verwendest Du denn?
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
Hallo NG, acos nun selbst implementiert, immer noch mist ... 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.
@Christian Habe das gleiche Problem mit 3,11 km. Konntest Du es lösen? Ich verwende keine atol oder sonstige Konvertierung.
warum kein strtod? (da hier an der zuverlässigkeit von atof gezweifelt wird)
@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.
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.