Forum: Mikrocontroller und Digitale Elektronik uC-Prog >>> Berechnungsfehler


von __Son´s B. (bersison)


Lesenswert?

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?

von Marc S. (marc_s86)


Lesenswert?

du rechnest mit integern.

1023/15=68

68*11.5=782

von M. K. (sylaina)


Lesenswert?

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

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

Ich tippe übrigens, dass auch hier wieder mal diese Zahl 1023 falsch 
ist, und es stattdessen 1024 heißen müsste...

von Peter II (Gast)


Lesenswert?

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.

von __Son´s B. (bersison)


Lesenswert?

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
von Marc_s86 (Gast)


Lesenswert?

__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

von Marc_s86 (Gast)


Lesenswert?

__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.

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

__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
von Falk B. (falk)


Lesenswert?

Das kommt darauf an . . .

Beitrag "Re: 1023 oder 1024"

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

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... ;-)

von DirkB (Gast)


Lesenswert?

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

von Marc S. (marc_s86)


Lesenswert?

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 :)

von Joachim B. (jar)


Lesenswert?

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.

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

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
von __Son´s B. (bersison)


Lesenswert?

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
von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

__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?

von DirkB (Gast)


Lesenswert?

__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.

von __Son´s B. (bersison)


Lesenswert?

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.

von Peter II (Gast)


Lesenswert?

__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.

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

__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
von __Son´s B. (bersison)


Lesenswert?

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.

von M. K. (sylaina)


Lesenswert?

__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.

von Marc S. (marc_s86)


Lesenswert?

__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.

von DirkB (Gast)


Lesenswert?

__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))

von __Son´s B. (bersison)


Lesenswert?

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
Noch kein Account? Hier anmelden.