Problem mit while()

OP #5925150
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
Gast #5925177
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.
Beitrag #5925187 wurde von einem Moderator gelöscht.
Moderator #5925296
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
Gast #5933418
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.
Gast #5933435
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.
Gast #5933725
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.
Gast #5933735
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 >?

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren