double auf Display und dann Rechenoperationen

Gast #3927728
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
Gast #3927793
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.
#3927817
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.
Gast #3927822
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

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