Hallo. Innerhalb einer Fehlersuche ist mir ein Berechnungsfehler aufgefallen, den ich nicht nachvollziehen kann; ________________________________________________________ #define OBER_BEREICH 1023/15*11.5 // sollte 784,3 heraus kommen #define UNTER_BEREICH 1023/15*10.5 // sollte 716,1 heraus kommen int main() ... uint16_t mit_wert; // altern. int64_t oder uint64_t keine Veränderung mit_wert=782; // Testwert, um Schwelle genau zu ermitteln if (mit_wert >= OBER_BEREICH) { LED_HIGH; } // sollte >=784 else if (mit_wert <= UNTER_BEREICH) { LED_LOW; } // sollte <=716 else { LED_MID; } ... ____________________________________________________________ Folgendes mit unterschiedlichen "mit_wert" empirisch ermittelt; LED_HIGH schaltet bei 782, nicht ab >=784 LED_LOW schaltet ab 714, nicht ab <= 716 Woher kommt die Ungenauigkeit?
Richtig, der Compiler weiß nicht dass mit float gerechnet werden soll, er sieht aber, dass das Ergebnis ein Integer werden soll also wird er dafür sorgen, dass erst gecastet wird und dann gerechnet. Schreibe also am besten mal:
1 | #define OBER_BEREICH (float)1023.0/15.0*11.5 // sollte 784,3 heraus kommen
|
2 | #define UNTER_BEREICH (float)1023.0/15.0*10.5 // sollte 716,1 heraus kommen
|
Ich tippe übrigens, dass auch hier wieder mal diese Zahl 1023 falsch ist, und es stattdessen 1024 heißen müsste...
Michael K. schrieb: > Richtig, der Compiler weiß nicht dass mit float gerechnet werden soll, > er sieht aber, dass das Ergebnis ein Integer werden soll seit wann soll das so sein? Das Ergebnis interessiert den Compiler nicht.
1 | #define OBER_BEREICH 1023.0/15*11.5 // sollte 784,3 heraus kommen
|
2 | #define UNTER_BEREICH 1023.0/15*10.5 // sollte 716,1 heraus kommen
|
reicht aus.
Lothar M. schrieb: > Ich tippe übrigens, dass auch hier wieder mal diese Zahl 1023 falsch > ist, und es stattdessen 1024 heißen müsste... 0 bis 1023 (1024 Werte) oder falsch Gedacht? Michael K. schrieb: > #define OBER_BEREICH (float)1023.0/15.0*11.5 // sollte 784,3 heraus > kommen Klingt logisch. Habe es mit (float) probiert, hier schaltet er erst bei ">=785", soll: ">=784" Nehme ich die Deklaration (uint64_t), reagiert die Auswertung genau so wie ohne Deklaration #define OBER_BEREICH 1023.0/15.0*11.5 Setze ich eine festen Wert ins Macro ein, funktioniert alles einwandfrei! #define OBER_BEREICH 784 Somit muss es an der Berechnung selber liegen!
:
Bearbeitet durch User
__Son´s B. schrieb: > Lothar M. schrieb: >> Ich tippe übrigens, dass auch hier wieder mal diese Zahl 1023 falsch >> ist, und es stattdessen 1024 heißen müsste... > 0 bis 1023 (1024 Werte) oder falsch Gedacht? > > Michael K. schrieb: >> #define OBER_BEREICH (float)1023.0/15.0*11.5 // sollte 784,3 heraus >> kommen > Klingt logisch. Habe es mit (float) probiert, hier schaltet er erst bei > ">=785", soll: ">=784" > Nehme ich die Deklaration (uint64_t), reagiert die Auswertung genau so > wie ohne Deklaration > #define OBER_BEREICH 1023.0/15.0*11.5 #define OBER_BEREICH (int)1023.0/15.0*11.5 // sollte 784 heraus kommen
__Son´s B. schrieb: > Setze ich eine festen Wert ins Macro ein, funktioniert alles > einwandfrei! > #define OBER_BEREICH 784 > Somit muss es an der Berechnung selber liegen! ja natürlich 784 ist ja auch kleiner als 784,3.
__Son´s B. schrieb: > 0 bis 1023 (1024 Werte) oder falsch Gedacht? Richtig: 1024 ist die Zahl, mit der beim 10-Bit-Wandler gerechnet wird, weil er eben 1024 Schritte machen kann. Aber wie gesagt: ein gern gemachter Fehler... ;-)
:
Bearbeitet durch Moderator
Falk B. schrieb: > Das kommt darauf an . . . ... ob man es richtig machen will oder schön. Vor allem aber muss man sich bewusst sein, dass eine Division durch 2^n-1 immmer komplizierter ist als eine duch 2^n. Dann darf man an der richtigen Stelle auch mal mit 1023 rechnen. > Beitrag "1023 oder 1024" Ein schöner Thread... ;-)
Marc_s86 schrieb: > #define OBER_BEREICH (int)1023.0/15.0*11.5 // sollte 784 heraus kommen Das wandelt erstmal die 1023.0 in ein int um um gleich danach ein double daraus zu machen, um die Division durch 15.0 zu berechnen. Etwas umstellen reicht aus und gegen Nebeneffekte nochmal in Klammern.
1 | #define OBER_BEREICH (11.5 * 1023 / 15) // sollte 784 heraus kommen
|
DirkB schrieb: > Marc_s86 schrieb: >> #define OBER_BEREICH (int)1023.0/15.0*11.5 // sollte 784 heraus kommen > > Das wandelt erstmal die 1023.0 in ein int um um gleich danach ein double > daraus zu machen, um die Division durch 15.0 zu berechnen. > > Etwas umstellen reicht aus und gegen Nebeneffekte nochmal in > Klammern.#define OBER_BEREICH (11.5 * 1023 / 15) // sollte 784 heraus > kommen das ist wohl die beste lösung :)
Lothar M. schrieb: > Richtig: 1024 ist die Zahl, mit der beim 10-Bit-Wandler gerechnet wird, > weil er eben 1024 Schritte machen kann. Aber wie gesagt: ein gern > gemachter Fehler... ;-) aber die ADC Ausgabe ist trotzdem 0-1023 wenn ich normiere zu 100% oder 1 muss ich immer die ADC Ausgabe / 1023 teilen damit am oberen Anschlag ADCmax / 1023 = 1 rauskommt. Da kann ich nicht mit 1024 rechnen, weder schön noch richtig. Lothar M. schrieb: > ... ob man es richtig machen will oder schön. Ich würde ja nie wagen dir zu widersprechen, dazu bist du einfach besser, aber hier erschliesst sich deine Logik für mich noch nicht.
Joachim B. schrieb: > damit am oberen Anschlag ADCmax 1023 = 1 rauskommt. Der Witz ist: 1023 ist nicht gleich 1,000 (*Vref) sondern es gilt: 1023 ist gleich 0,999 (*Vref) Aber wenn du gerne willst, dass am "oberen" Ende 1,0000 herauskommt, dann musst du natürlich durch 1023 teilen, weil sonst die Steigung der Korrektur zu flach ist. Das wurde aber im verlinkten Thread bis zum Umfallen ausdiskutiert. Bei 8-Bit-Rechnern gilt dann zusätzlich: bis diese 1023er-Division beendet ist, bin ich mit meinem 1024er-Programm schon weit, weit weg... ;-)
:
Bearbeitet durch Moderator
DirkB schrieb: > #define OBER_BEREICH (11.5 * 1023 / 15) welchen Unterschied gibt es zu; #define OBER_BEREICH 1023.0/15.0*11.5 Lothar M. schrieb: >> Beitrag "1023 oder 1024" > Ein schöner Thread... ;-) W U N D E R B A R! Werde zukünftig der einfacheren Lesbarkeit und dem Compiler zu liebe 1024 benutzen, obwohl mir meine Logik 1023 (0-1023) angibt.
:
Bearbeitet durch User
__Son´s B. schrieb: > obwohl mir meine Logik 1023 (0-1023) angibt. Es ist deine Intuition, die dir das angibt. Denn die Logik würde 1024 angeben... ;-) Oder mal was anderes aus der selben Ecke: Wieviele Takte braucht ein Zähler von 0 bis 1023? Wieviele Schritte hat eine 10-Bit PWM?
__Son´s B. schrieb: > DirkB schrieb: >> #define OBER_BEREICH (11.5 * 1023 / 15) > welchen Unterschied gibt es zu; > #define OBER_BEREICH 1023.0/15.0*11.5 Wenn du irgendwie mit dem Makro rechnest und einen Operator mit gleicher oder höherer Priorität als / und * hast, gibt es Probleme. Darum die Klammern. 1568.6 / (11.5 * 1023 / 15) == 2.0 1568.6 / 1023.0/15.0*11.5 == 1.17555 Dadurch, dass zuerst eine double-Literal steht, wird der Rest auch als double berechnet. Am Wert ändert sich (gegenüber dem Bsp) nichts.
Ok, habe mehrere Varianten nacheinander ausprobiert; #define OBER_BEREICH (11.5 * 1024 / 15) // == 785,07 #define OBER_BEREICH (1024 / 15 * 11,5) // == 785,07 #define OBER_BEREICH 1024 / 15 * 11,5 // == 785,07 ... mit_wert=785; // Schwellwert if (mit_wert >= OBER_BEREICH) // soll ab 785 und grösser ausgeführt werden { LED_HIGH; } ... Ausgang schaltet bei allen Varianten erst ab 786, statt 785. Haarspalterei? Dieses war ein Prog-test. Später werde ich die Konstante #define OBER_BEREICH 785 einsetzen. Um das Prog schlank zu halten und Rechneleistung zu sparen.
__Son´s B. schrieb: > Um das Prog schlank zu halten und Rechneleistung zu sparen. warum sollte das etwas sparen? Das Optimiert der Compiler doch weg.
__Son´s B. schrieb: > Dieses war ein Prog-test. Später werde ich die Konstante > #define OBER_BEREICH 785 > einsetzen. Um das Prog schlank zu halten und Rechneleistung zu sparen. Diese Berechnung kostet nur 1x Zeit (beim Compilieren) und das Ergebnis braucht auch nicht mehr Platz. Nur der Quellcode braucht ein paar Byte mehr.. __Son´s B. schrieb: > Ok, habe mehrere Varianten nacheinander ausprobiert; > #define OBER_BEREICH (11.5 * 1024 / 15) // == 785,07 > #define OBER_BEREICH (1024 / 15 * 11,5) // == 785,07 > #define OBER_BEREICH 1024 / 15 * 11,5 // == 785,07 Das stimmt schon, aber was kommt da heraus: Ergebnis = OBER_BEREICH/3; Ist das Ergebnis in allen 3 Fällen das Selbe?
:
Bearbeitet durch Moderator
Peter II schrieb: > __Son´s B. schrieb: >> Um das Prog schlank zu halten und Rechneleistung zu sparen. > > warum sollte das etwas sparen? Das Optimiert der Compiler doch weg. Ok & Danke, war mir gerade nicht bewusst! Lothar M. schrieb: >> Ok, habe mehrere Varianten nacheinander ausprobiert; >> #define OBER_BEREICH (11.5 * 1024 / 15) // == 785,07 >> #define OBER_BEREICH (1024 / 15 * 11,5) // == 785,07 >> #define OBER_BEREICH 1024 / 15 * 11,5 // == 785,07 > Das stimmt schon, aber was kommt da heraus: Dann verstehe ich immer noch nicht die Ungenauigkeit von 1 Step.
__Son´s B. schrieb: > Lothar M. schrieb: >>> Beitrag "1023 oder 1024" >> Ein schöner Thread... ;-) > W U N D E R B A R! > Werde zukünftig der einfacheren Lesbarkeit und dem Compiler zu liebe > 1024 benutzen, obwohl mir meine Logik 1023 (0-1023) angibt. Das liegt aber nur daran, dass man folgendes im Datenblatt überlesen hat: Beispiel aus dem Datenblatt für den Atmega328 (Seite 242): > The minimum value represents GND and the maximum value represents the > voltage on the AREF pin minus 1 LSB.
__Son´s B. schrieb: > Peter II schrieb: >> __Son´s B. schrieb: >>> Um das Prog schlank zu halten und Rechneleistung zu sparen. >> >> warum sollte das etwas sparen? Das Optimiert der Compiler doch weg. > Ok & Danke, war mir gerade nicht bewusst! > > Lothar M. schrieb: >>> Ok, habe mehrere Varianten nacheinander ausprobiert; >>> #define OBER_BEREICH (11.5 * 1024 / 15) // == 785,07 >>> #define OBER_BEREICH (1024 / 15 * 11,5) // == 785,07 >>> #define OBER_BEREICH 1024 / 15 * 11,5 // == 785,07 >> Das stimmt schon, aber was kommt da heraus: > Dann verstehe ich immer noch nicht die Ungenauigkeit von 1 Step. Das ist keine Ungenauigkeit, du hast es nur noch immer nicht verstanden. Lies den thread.
__Son´s B. schrieb: > Ok, habe mehrere Varianten nacheinander ausprobiert; > > #define OBER_BEREICH (11.5 * 1024 / 15) // == 785,07 > #define OBER_BEREICH (1024 / 15 * 11,5) // == 785,07 > #define OBER_BEREICH 1024 / 15 * 11,5 // == 785,07 > ... Das stimmt nicht! Zumal du da auch Zahlen mit Komma (,) hast. Das Ergebnis ist ein double. Dann wird auch der Vergleich asl double ausgeführt.
1 | mit_wert=785; // Schwellwert |
2 | if (mit_wert >= 785.07) |
Wenn es int sein soll:
1 | #define OBER_BEREICH ((int)(11.5 * 1024 / 15))
|
DirkB schrieb: > Zumal du da auch Zahlen mit Komma (,) hast. Klar! Macht der Gewohnheit... Ist auch nur in diesem Forum beim Abtippen passiert.
:
Bearbeitet durch User
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.