Forum: Mikrocontroller und Digitale Elektronik Geschickt runden


von Curby (Gast)


Lesenswert?

Moin,


wenn ich eine Zahl wie 400.99999999999999 als double habe, wie kann ich 
diese geschickt auf 401 runden? Alle anderen normalen Kommazahlen sollen 
nicht gerundet werden.

Also diese Grenzwerte wegrunden?

mfg

von Tommy T. (tommy2000)


Lesenswert?

y = 400.99999999999999;
y = (int)(y + 0.00000000000001)

Rundet alle Zahlen auf 401 die >= 400.99999999999999 sind.

von Ralph (Gast)


Lesenswert?

int(400.99999999999999 + 0.x5 )
x sind so viel "0" wie du Stellen + 1 behalten willst

Denk mal über Integerberechnung nach.
Ist auf µC meistens die bessere Wahl.

von Tommy T. (tommy2000)


Lesenswert?

Tommy T. schrieb:
> y = 400.99999999999999;
> y = (int)(y + 0.00000000000001)
>
> Rundet alle Zahlen auf 401 die >= 400.99999999999999 sind.
>
Eigentlich ist es sogar besser, wenn du es nur so machst:

y = y + 0.00000000000001;

Dann musst du vor dem Runden nicht den Wert prüfen. Der Fehler für alle 
wird dadurch (hoffentlich) minimal und ob man jetzt 400.99999999999999 
oder 401.0 hat ist ja nur für die Ausgabe relevant.

von Curby (Gast)


Lesenswert?

Ralph schrieb:
> Denk mal über Integerberechnung nach.
> Ist auf µC meistens die bessere Wahl.

Was bringen mir Integer, wenn ich Frequenzen aus einem Integer berechne 
(Timer werte) und den Wert aufm Display darstellen will?

Ich hatte versucht, den Double Wert zu runden und dann jeweils zu 
addieren und subtrahieren. Wenn der Abstand dann kleiner als 0.001 ist, 
soll gerundet werden. Das hat aber nicht funktioniert, da bei dem Wert 
immer ne glatte 0 heraus kommt.

von Werner (Gast)


Lesenswert?

Curby schrieb:
> wenn ich eine Zahl wie 400.99999999999999 als double habe, wie kann ich
> diese geschickt auf 401 runden?

400.99999999999999 ist nur ein Artefakt der Dezimaldarstellung bei 
deiner Ausgabe. Beschränke deine Ausgabe auf die Zahl der relevanten 
Stellen und alles wird gut.

von Curby (Gast)


Lesenswert?

Werner schrieb:
> Curby schrieb:
>> wenn ich eine Zahl wie 400.99999999999999 als double habe, wie kann ich
>> diese geschickt auf 401 runden?
>
> 400.99999999999999 ist nur ein Artefakt der Dezimaldarstellung bei
> deiner Ausgabe. Beschränke deine Ausgabe auf die Zahl der relevanten
> Stellen und alles wird gut.

Im sprintf wird daraus 400.999 bei %3.3f. Daraus sollte dann 401 werden.
Das problem des Rundens betrifft in diesem Fall natürlich nur die Grenze 
zur nächstgrößeren Zahl. Aus 400.0000000001 wird der denke ich mal 
400.000 machen.

Ich habe jetzt folgende umständliche Lösung verwendet, die auch 
funktioniert. Die Variable freq_soll ist die betreffene Variable.

if((float)round(freq_soll)-freq_soll < 0.001 && 
(float)round(freq_soll)-freq_soll > 0) freq_soll = round(freq_soll);

von Tommy T. (tommy2000)


Lesenswert?

Curby, verwende %3.3f und addiere 0.0001 auf den Wert, dann passt die 
Ausgabe.

von Werner (Gast)


Lesenswert?

Curby schrieb:
> Im sprintf wird daraus 400.999 bei %3.3f.

Dann ist das ein Problem der Konvertierung von sprintf.

von Martin S. (sirnails)


Lesenswert?

> Was bringen mir Integer, wenn ich Frequenzen aus einem Integer berechne
> (Timer werte) und den Wert aufm Display darstellen will?

Sie bringen das mathematisch einzig richtige Ergebnis. Du kannst durch 
Berechnungen keine höhere Genauigkeit erzeugen, als Deine Ausgangswerte 
besitzen. Und wenn die ungenaueste Zahl NULL Nachkommastellen hat, dann 
darf das Ergebnis auch nur NULL Nachkommastellen besitzen. Alles andere 
ist ein Lügenbold, Schätzeisen, oder wie auch immer Du das nennst.

von J. S. (engineer) Benutzerseite


Lesenswert?

Eben, denn wer will im allgemeinen Fall entscheiden, ob die Zahl 
zufällig oder zurecht diesen Wert angenommen hat. Das Einige, was es zu 
beachten gibt, ist, sie so zu runden, dass kein wesentlich grösserer 
Fehler entsteht, als die Zahl ohnehin in sich trägt und aus Sicht des 
Ingenieurs ist es sogar nötig, sie so zu runden, dass nicht der Eindruck 
einer künstlichen Genauigkeit entsteht, als nicht zuviele Stellen 
anzuzeigen.


Was mir noch nicht klar ist:

Warum funktioniert die Addition von 0,5 nicht?

Die 401.49999 müssten doch auch korrekt abgerundet werden. Angenommen, 
die 3. Stelle soll erhalten werden, dann müssten mathematisch 0,0005 
addiert werden. 401,000499000 und damit genau 401,000.

Excel kann das auch:

400,9999
+ 0,0005
401,0004

wobei Excel bereits auf 401 rundet, wenn man die 400,9999999 mit 
zuvielen Stellen eingibt :-)

Ein anderes Problem ist, dass man bei der Gaussklammerfunktion oder 
Gaussrundung nicht mit 1,0 arbeiten darf sondern mit 0,999999999 rechnen 
muss.

von Curby (Gast)


Lesenswert?

Martin Schwaikert schrieb:
>> Was bringen mir Integer, wenn ich Frequenzen aus einem Integer berechne
>> (Timer werte) und den Wert aufm Display darstellen will?
>
> Sie bringen das mathematisch einzig richtige Ergebnis. Du kannst durch
> Berechnungen keine höhere Genauigkeit erzeugen, als Deine Ausgangswerte
> besitzen. Und wenn die ungenaueste Zahl NULL Nachkommastellen hat, dann
> darf das Ergebnis auch nur NULL Nachkommastellen besitzen. Alles andere
> ist ein Lügenbold, Schätzeisen, oder wie auch immer Du das nennst.

Da will ich jetzt doch mal nachhaken. Z.b. ich habe den Timerwert 10000 
und 1 entspricht 1/F_CPU Sekunden, dann ist meine Frequenz ja 
F_CPU/Timerwert. Der ursprüngliche Wert ist eine INT das ist klar, aber 
das Ergebnis kann ja allmöögliche Kommastellen annehmen, da brauch ich 
doch eine Kommazahl, eben float oder double.

von Karl H. (kbuchegg)


Lesenswert?

> 401,00049900

Höchts wahrscheinlich deshalb, weil deine 401,00049900 in Wirklichkeite 
eben 401.0004989999999 sind, welche dann bei der Ausgabe auf 401.000499 
aufgerundet wurden.

> Excel kann das auch
Excel rechnet aber auch nicht mit float. Es macht nun mal einen 
Unterschied, ob du 6 signifikante Stellen hast oder 15.

von Markus W. (Firma: guloshop.de) (m-w)


Lesenswert?

Curby schrieb:
> wenn ich eine Zahl wie 400.99999999999999 als double habe, wie kann ich
> diese geschickt auf 401 runden? Alle anderen normalen Kommazahlen sollen
> nicht gerundet werden.

Schaut ja schlimm aus. :-)
Nimm doch Festkommazahlen, dann hast du solche Probleme gar nicht erst. 
Zusätzlich werden die Berechnungen deutlich schneller.

http://www.mikrocontroller.net/articles/Festkommaarithmetik

von Karl H. (kbuchegg)


Lesenswert?

Curby schrieb:

> Da will ich jetzt doch mal nachhaken. Z.b. ich habe den Timerwert 10000
> und 1 entspricht 1/F_CPU Sekunden, dann ist meine Frequenz ja
> F_CPU/Timerwert. Der ursprüngliche Wert ist eine INT das ist klar, aber
> das Ergebnis kann ja allmöögliche Kommastellen annehmen, da brauch ich
> doch eine Kommazahl, eben float oder double.

Das Problem ist ein anderes.
Du musst dich fragen, wieviele Kommastellen sind denn überhaupt 
relevant? Und darauf musst du deine Berechnung anpassen.
Und: Du musst beim Rechnen mit Floating Point immer berücksichtigen, 
dass du im Rechner nur eine endliche Genauigkeit hast. Die naive 
Annahme, das Floating Point Rechnerei genau gleich funktioniert wie in 
der Mathematik, ist ein Irrglaube.

von eProfi (Gast)


Lesenswert?

> Der ursprüngliche Wert ist eine INT das ist klar, aber das Ergebnis
> kann ja allmöögliche Kommastellen annehmen, da brauch ich
> doch eine Kommazahl, eben float oder double.

nein:
Du erweiterst den Quotenten um 10 oder 100 und schmuggelst bei der 
Ausgabe ein Komma rein:
z.B. Runden und Ausgeben mit 2 Nachkommastellen
F_CPU = 16000000
Timer = 3

Berechnung:
FoutMal100 = F_CPU * 100 / timer ;
FoutVorkomma  = FoutMal100 / 100 ;
FoutNachkomma = FoutMal100 % 100 ;

von Curby (Gast)


Lesenswert?

eProfi schrieb:
>> Der ursprüngliche Wert ist eine INT das ist klar, aber das Ergebnis
>> kann ja allmöögliche Kommastellen annehmen, da brauch ich
>> doch eine Kommazahl, eben float oder double.
>
> nein:
> Du erweiterst den Quotenten um 10 oder 100 und schmuggelst bei der
> Ausgabe ein Komma rein:
> z.B. Runden und Ausgeben mit 2 Nachkommastellen
> F_CPU = 16000000
> Timer = 3
>
> Berechnung:
> FoutMal100 = F_CPU * 100 / timer ;
> FoutVorkomma  = FoutMal100 / 100 ;
> FoutNachkomma = FoutMal100 % 100 ;

Ich hab aber Werte im Timer von 0-262143 (jap, es handelt sich hier 
sogar um eine Long)? Das Fließkommaberechnung nicht exakt genau ist, ist 
mir durchaus bewusst. Aber so genau, wie ich es brauche wird es wohl 
sein.

von Werner (Gast)


Lesenswert?

Martin Schwaikert schrieb:
> Und wenn die ungenaueste Zahl NULL Nachkommastellen hat, dann
> darf das Ergebnis auch nur NULL Nachkommastellen besitzen. Alles andere
> ist ein Lügenbold, Schätzeisen, oder wie auch immer Du das nennst.

Was hat das mit der Zahl der Nachkommastellen zu tun. Die kann man 
beliebig ändern, indem man ein Spannung z.B. statt in mV in V angibt. 
Entscheidend ist die Anzahl der gültigen Stellen. Ein Widerstand von 
2,26MΩ wird nicht dadurch genauer oder ungenauer, dass man ihn als 
2260000Ω angibt.

von dummschwaetzer (Gast)


Lesenswert?

meinezahl=ceil(meinezahl*1000)/1000
oder
meinezahl=floor(meinezahl*1000)/1000
ist dein freund

von m. schwaikert (Gast)


Lesenswert?

Werner schrieb:
> Martin Schwaikert schrieb:
>> Und wenn die ungenaueste Zahl NULL Nachkommastellen hat, dann
>> darf das Ergebnis auch nur NULL Nachkommastellen besitzen. Alles andere
>> ist ein Lügenbold, Schätzeisen, oder wie auch immer Du das nennst.
>
> Was hat das mit der Zahl der Nachkommastellen zu tun. Die kann man
> beliebig ändern, indem man ein Spannung z.B. statt in mV in V angibt.
> Entscheidend ist die Anzahl der gültigen Stellen. Ein Widerstand von
> 2,26MΩ wird nicht dadurch genauer oder ungenauer, dass man ihn als
> 2260000Ω angibt.

Oh ja richtig. gültige- nicht Nachkommastellen. verzeihung.

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.