Forum: PC-Programmierung Problem mit while()


von Welle 🧐 S. (w3llschmidt)


Lesenswert?

Warum wird das zweite while() aufgerufen???
1
double throttle = 0;
2
3
throttle_control() {
4
5
double f=0.000000;
6
7
  for(;;) { 
8
9
    if (throttle > f) {
10
11
      while(throttle > f) {         
12
13
        f+=0.100000;
14
        printf("B %f\n",f );
15
16
      }
17
18
      while(throttle < f) {        
19
20
        f-=0.100000;
21
        printf("C %f\n",f );
22
23
      }
24
25
    } else { 
26
27
      //wenn throttle negativ
28
29
    }
30
31
  vTaskDelay(1000 / portTICK_PERIOD_MS);
32
  }
33
34
}
35
36
37
void app_main() {
38
39
  xTaskCreate(&throttle_control, "throttle_control", 2048, NULL, 30, NULL);
40
41
  throttle=30;
42
43
}
1
B 27.800000
2
B 27.900000
3
B 28.000000
4
B 28.100000
5
B 28.200000
6
B 28.300000
7
B 28.400000
8
B 28.500000
9
B 28.600000
10
B 28.700000
11
B 28.800000
12
B 28.900000
13
B 29.000000
14
B 29.100000
15
B 29.200000
16
B 29.300000
17
B 29.400000
18
B 29.500000
19
B 29.600000
20
B 29.700000
21
B 29.800000
22
B 29.900000
23
B 30.000000
24
C 29.900000
25
B 30.000000
26
C 29.900000
27
B 30.000000
28
C 29.900000
29
B 30.000000
30
C 29.900000
31
B 30.000000
32
C 29.900000
33
B 30.000000

: Verschoben durch User
von Dussel (Gast)


Lesenswert?

Warum nicht?
Durch das Hochzählen wird f größer und ist irgendwann so groß, dass f 
größer als throttle ist.

von Johannes S. (Gast)


Lesenswert?

Rundungsfehler? Float auf Gleichheit zu vergleichen ist selten gut.

von Dussel (Gast)


Lesenswert?

Ach, jetzt verstehe ich das Problem. :D
Das kann sein.

von Dr. Sommer (Gast)


Lesenswert?

Die Zahl 0.1 gibt's im Binärsystem nicht, genau so wie es 1/3 im 
Dezimalsystem nicht (mit endlich vielen Ziffern) gibt. Daher wird 
stattdessen 0.09999irgendwas genommen. Da die Ausgabe mit printf rundet, 
sieht man das nicht.

Daher wird f erst zu 29.999irgendwas (kleiner 30) und dann zu 
30,999irgendwas (größer 30). Wenn du die Zahlen mit mehr Genauigkeit 
ausgibst kannst du das nachvollziehen. Kann auch sein dass es umgekehrt 
ist mit 0.1000...irgendwas.

Merke: Bei float nie davon ausgehen dass Zahlen sich genau darstellen 
lassen. Immer bedenken dass bei wiederholter Summierung sich Fehler 
aufsummieren. Dran denken das n mal x addieren nicht gleich x*n ist. Bei 
Vergleichen immer unscharf mit Toleranzbereich rechnen; sonst bringen 
winzige Unsicherheiten das System zum Kippen. Die Abstände zwischen den 
darstellbaren Zahlen werden größer. Diese ganzen Probleme umgeht man 
übrigens, indem man fixed point rechnet.

von Karl M. (Gast)


Lesenswert?

Noch ein Hinweis,

je nach Zielsystem ist sizeof(double) = sizeof(float).

von Welle 🧐 S. (w3llschmidt)


Lesenswert?

Dr. Sommer schrieb:
> 30,999irgendwas (größer 30)
> übrigens, indem man fixed point rechnet.

Danke!

Beitrag #5925187 wurde vom Autor gelöscht.
von Yalu X. (yalu) (Moderator)


Lesenswert?

Den von Dr. Sommer beschriebenen Effekt kannst du sichtbar machen, indem
du in den beiden printfs das Format %f in %.20f änderst und damit die
Anzahl der angezeigten Nachkommastellen erhöhst. Auf meinem PC sehen die
Ergebnisse dann so aus:

1
B 0.10000000000000000555
2
B 0.20000000000000001110
3
B 0.30000000000000004441
4
B 0.40000000000000002220
5
B 0.50000000000000000000
6
B 0.59999999999999997780
7
B 0.69999999999999995559
8
B 0.79999999999999993339
9
...
10
B 29.70000000000015205615
11
B 29.80000000000015347723
12
B 29.90000000000015489832
13
B 30.00000000000015631940
14
C 29.90000000000015489832
15
B 30.00000000000015631940
16
C 29.90000000000015489832
17
B 30.00000000000015631940

von Ron Jeremy (Gast)


Lesenswert?

Anfängerfehler Nr 135:
Man vergleicht Fliesskommatpyen nicht mit <,> oder = sondern über ein 
delta das man aus float bildet. Das gilt auch wenn das eine ein 
Fliesskommatyp ist und der andere ein Integer, man hat dort das selbe 
Problem.

von mh (Gast)


Lesenswert?

Ron Jeremy schrieb:
> Anfängerfehler Nr 135:
> Man vergleicht Fliesskommatpyen nicht mit <,> oder = sondern über ein
> delta das man aus float bildet. Das gilt auch wenn das eine ein
> Fliesskommatyp ist und der andere ein Integer, man hat dort das selbe
> Problem.

Das ist nicht sehr hilfreich. Wie will man mit dem delta vergleichen, 
wenn man nicht <, > oder == benutzen darf? Es ist auch in vielen Fällen 
in Ordnung floatVariable == 0 zu prüfen.

von Ron Jeremy (Gast)


Lesenswert?

mh schrieb:
> Das ist nicht sehr hilfreich. Wie will man mit dem delta vergleichen,
> wenn man nicht <, > oder == benutzen darf?
Man vergleicht nat. das Delta mit diesen Operatoren, muss man das noch 
erklären?

> Es ist auch in vielen Fällen
> in Ordnung floatVariable == 0 zu prüfen.
"In vielen Fällen" -> eben nicht, das verschlimmert das Problem noch 
mehr weil der Problemfall dann noch seltener auftritt und somit noch 
schwerer zu entdecken ist wenn man diese Sorte Probleme nicht kennt.

Das ist wie bei Threadproblemen: Funktioniert meistens ohne 
Synchronisation aber irgendwann krachts (was noch gut ist, dann sieht 
man sofort hier stimmt was nicht) oder schleichen sich seltsame Fehler 
ein (klassisches Beispiel Bankkkontoabbuchungen) und dann steht der Laie 
wie der Ochs vorm Berg und weiss nicht warum.

Besser gleich richtig machen und nicht rumpfuschen.

von mh (Gast)


Lesenswert?

Ron Jeremy schrieb:
> mh schrieb:
>> Das ist nicht sehr hilfreich. Wie will man mit dem delta vergleichen,
>> wenn man nicht <, > oder == benutzen darf?
> Man vergleicht nat. das Delta mit diesen Operatoren, muss man das noch
> erklären?

Und wieso darf man das delta mit diesen Operatoren vergleichen und 
andere Fließkommazahlen nicht? Und wo genau besteht überhaupt ein 
Problem mit < und >?

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.