Forum: Mikrocontroller und Digitale Elektronik double auf Display und dann Rechenoperationen


von u_SD (Gast)


Lesenswert?

Vor einiger Zeit hatte ich einen Thread geöffnet und eine Frage bzgl. 
der Anzeige von Doubles auf einem Display gestellt. Dies sah in etwa so 
aus:
1
double amount1 = 0;
2
double amount2 = 0;
3
double amount3 = 0;
4
unsigned char anzahl1 = 3;
5
unsigned char anzahl2 = 4;
6
unsigned char anzahl3 = 54;
7
amount1 = anzahl1*(double)0.01;
8
amount2 = anzahl2*(double)0.02;
9
amount3 = anzahl3*(double)0.05;
10
double_to_Display(amount1);
11
double_to_Display(amount2);
12
double_to_Display(amount3);

Da der uc rundet und z.b. 0.01 in Wirkilichkeit 0.0999999999; 0.02 = 
0.19999 etc. ist kam es bei der Rechenoperation stets zu falschen 
Anzeigen auf dem Display.

Herr Miller hat den folgenden Tip für die anzeige gegeben, der für die 
Anzeige auch funktioniert hat:
1
amount1 = anzahl1*(double)0.01 + 0.005;
2
amount2 = anzahl2*(double)0.02 + 0.005;
3
amount3 = anzahl3*(double)0.05+ 0.005;
4
double_to_Display(amount1);
5
double_to_Display(amount2);
6
double_to_Display(amount3);

Jetzt kommt jedoch ein weiteres Problem auf, wenn ich wieder mit diesen 
Beträgen rechnen will, beispielsweise...
1
amount1 = anzahl1*(double)0.01 + 0.005;
2
amount2 = anzahl2*(double)0.02 + 0.005;
3
amount3 = anzahl3*(double)0.05+ 0.005;
4
double_to_Display(amount1 + amount2 + amount3);
5
// oder
6
double_to_Display(amount1 -2*5);

führt wieder zu einer falschen Anzeige!

Welcher Weg bietet sich an um diese Rundungsproblematik bei double 
Werten zu umgehen?

Danke

von Rolf M. (rmagnus)


Lesenswert?

Du mußt bei der Ausgabe - und nur da - runden, nicht bei jedem 
Zwischenwert.

von Kai S. (zigzeg)


Lesenswert?

Eigentlich sollte man das Runden in double_to_Display() einbauen, und 
dort nur eine begrenzte Stellenanzahl ausgeben, und das mit korrekter 
Rundung !

von u_SD (Gast)


Lesenswert?

Kai S. schrieb:
> Eigentlich sollte man das Runden in double_to_Display() einbauen,
> und
> dort nur eine begrenzte Stellenanzahl ausgeben, und das mit korrekter
> Rundung !

hmmm, dies ist mir noch nicht so ganz klar: Hier mal meine Funktion:
1
void integertodisplay_mehrstellig_double(double zahl, unsigned char pos)
2
{
3
    unsigned char zweitenachkommastelle = fmod(zahl*100,10);
4
    // aufrunden
5
    unsigned char erstenachkommastelle = fmod(zahl*10,10);
6
//    unsigned char erstenachkommastelle = ceil(fmod(zahl*10,10));
7
    unsigned char einser = fmod(zahl,10);
8
    unsigned char zehner = fmod(zahl/10,10);
9
    unsigned char hunderter = fmod(zahl/100,10);
10
    unsigned char tausender = fmod(zahl/1000,10);
11
12
    integertodisplay_1stellig(zweitenachkommastelle,pos);
13
    pos--;
14
    integertodisplay_1stellig(erstenachkommastelle, pos);
15
    pos--;
16
    integertodisplay_1stellig(einser, pos);
17
    pos--;
18
    if(zehner > 0 || hunderter > 0 || tausender > 0)
19
    {
20
        integertodisplay_1stellig(zehner,pos);
21
        pos--;
22
    }
23
    if(hunderter > 0 || tausender > 0)
24
    {
25
        integertodisplay_1stellig(hunderter, pos);
26
        pos--;
27
    }
28
    if(tausender > 0)
29
    {
30
        integertodisplay_1stellig(tausender, pos);
31
    }
32
33
}

Wo und wie genau könnte ich hier die Rundung mit einbauen?
1
void integertodisplay_mehrstellig_double(double zahl, unsigned char pos)
2
{
3
zahl = zahl + 0.005;
4
...
5
}
...
Nur bei der Ausgabe ist einleuchtend und sollte auch so funktionieren. 
Es ist halt etwas umständluich bei jeder Ausgabe die Rundung mit 
einzubauen.

von (prx) A. K. (prx)


Lesenswert?

u_SD schrieb:
> Nur bei der Ausgabe ist einleuchtend und sollte auch so funktionieren.
> Es ist halt etwas umständluich bei jeder Ausgabe die Rundung mit
> einzubauen.

Es gibt 2 Möglichkeiten, solche Schmutzeffekte zu vermeinden.

(1) Man sorgt vor der Konvertierung in Dezimalstellen dafür, dass man 
hinter der letzten anzuzeigenden Stelle garantiert etwas darüber liegt, 
nicht darunter.

(2) Man konvertiert eine Stelle mehr ins Dezimalformat und rundet dann 
im Dezimalformat.

: Bearbeitet durch User
von u_SD (Gast)


Lesenswert?

> Es gibt 2 Möglichkeiten, solche Schmutzeffekte zu vermeinden.
>
> (1) Man sorgt vor der Konvertierung in Dezimalstellen dafür, dass man
> hinter der letzten anzuzeigenden Stelle garantiert etwas darüber liegt,
> nicht darunter.


OK, danke schön. Genau dies sollte ich ja mit

zahl = zahl + 0.005;

erreichen

von Purzel H. (hacky)


Lesenswert?

Ich wuerde die zwete Version vorziehen. Wert mal 10000 multiplizieren, 
nach Integer runden und dann das Komma um 4 Stellen verschieben.

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.