Forum: Compiler & IDEs 1/0.002 = 499 Wie krieg ich da 500 raus?


von Stephan S. (outsider)


Lesenswert?

Ich hab schon viel gesucht und es liegt wohl an Ungenauigkeiten von 
float, aber ich konnte nichts finden wie ich das Problem in den Griff 
bekomme. Eigentlich müsste doch ein Float vom Wertebereich und der 
Genauigkeit da locker reichen?

Es gibt auch ein Application Note von Atmel zu Funktionen zu Divisionen, 
aber da gehts nur um ganzzahlige Werte.

Da muss es doch eine Standardlösung geben für sowas, das Problem hat man 
doch bestimmt immer wieder.

Es geht nicht nur um diesen einen Wert, sondern darum dass die 
Ergebnisse immer stimmen. Diesen Wert hab ich nur zufällig gefunden.

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

>1/0.002 = 499
also    1/0.002 = 499.0 ?
oder    1/0.002 = 499.999976251 ?

Wenn danach ein Integer daraus werden soll:
1/0.002 + 0.5 = 500

Stichwort: Runden
Ein einfacher cast auf Integer schneidet nur die Nachkommastellen ab.

>Float vom Wertebereich ... und ... Genauigkeit da locker reichen?
Float hat einen sehr grossen Wertebereich (wegen des Exponenten),
aber nur eine Genauigkeit von 23 Bit (Mantisse), das ist weniger als 
long (32Bit).
Das Verhälthis 500/499.999976251 gibt genau die maximal erreichbare 
Genauigkeit in Dezimaldarstellung an: ca. 7 signifikante Stellen
(ergibt sich aus 2^23 = 8388608).
Siehe auch http://de.wikipedia.org/wiki/IEEE_754

Wenn du genauer rechnen willst, brauchst du ein anderes Zahlenformat.

von Freizeitbastler (Gast)


Lesenswert?

Hallo,

nein, die Genaugkeit reicht nicht für eine exakte Rechnung, da Zehntel 
nicht exakt als Binärbruch dargestellt werden können. Wenn Du das 
Ergebnis auf 7 oder schlimmstenfalls 6 Dezimalstellen rundest, sieht es 
wieder gut aus.

Schöne Grüße, Peter

von Braten (Gast)


Lesenswert?

Hmmm... Gibt es dazu ein Warning?

ich hätte jetzt mal ganz grob vermutet (meine c vorlesungen sind schon 
etwas länger her), dass du 1.0/0.002 machen muss.

sonst nimmt er 1 als integer.

Probier es mal aus, bin mir wie gesagt nicht mehr so sicher :-)

von Stephan S. (outsider)


Lesenswert?

Lothar Miller wrote:
>>1/0.002 = 499
> also    1/0.002 = 499.0 ?
> oder    1/0.002 = 499.999976251 ?

Ja, genau da liegt das Problem, hab ich übersehen dass beim casten zu 
Int der Rest einfach abgeschnitten wird.

> Wenn danach ein Integer daraus werden soll:
> 1/0.002 + 0.5 = 500

Ich bin nicht so sicher ob ich richtig liege, aber wenn ichs recht 
verstehe passt das Konstukt mit "+0,5" für jede möglich Division, oder?

Und wenn ich das weiter denke: Im Prinzip würde es reichen nicht 0,5 
sondern nur so viel zu addieren wie beim float mit der jeweiligen 
Genauigkeit maximal als Fehler auftreten kann, oder? Aber wenn 0,5 
universell passt dann mach ich das natürlich immer so und meine 
Anwendung ist gerettet, vielen Dank!

1.0/0.002 brachte übrigens keine Lösung des Problems, es ist schon die 
Sache mit dem Runden.

von Simon K. (simon) Benutzerseite


Lesenswert?

Stephan S. wrote:
> Ich bin nicht so sicher ob ich richtig liege, aber wenn ichs recht
> verstehe passt das Konstukt mit "+0,5" für jede möglich Division, oder?
Ja, zumindest fast. Bei negativen Zahlen musst du -0,5 rechnen:
1
unsigned long Round(double Value)
2
{
3
    if (Value < 0)
4
        return (unsigned long) (Value - 0.5)
5
    else
6
        return (unsigned long) (Value + 0.5)
7
}

> 1.0/0.002 brachte übrigens keine Lösung des Problems, es ist schon die
> Sache mit dem Runden.
Nein, zwischen
1
1/0.002
und
1
1.0/0.002
gibt es aus C-Sicht keinen Unterschied. In beiden Fällen wird die 
Division als double ausgeführt.

von bohner (Gast)


Lesenswert?

ebenfalls besteht die möglichkeit aus der stdlib "math.h" sich der 
funktionen ceil() bzw. floor() zu bedienen.

von Wolfgang B. (logox2)


Lesenswert?

Gehts oder kannst du nicht vielleicht (1*x/(0,002*x)) = 500 rechnen? mit 
x = 1000 wärst du im reinen int-Bereich.

von Stephan S. (outsider)


Lesenswert?

bohner wrote:
> ebenfalls besteht die möglichkeit aus der stdlib "math.h" sich der
> funktionen ceil() bzw. floor() zu bedienen.

Das setzt doch aber soweit ich das grad verstehe voraus dass ich weiß ob 
der Rundungsfehler die Zahl kleiner oder größer macht als ich erwarte. 
Kann man das generell im Voraus wissen?

Gibts nicht einfach eine Funktion die auf ganze Zahlen rundet wie man es 
gewohnt ist ohne einfach was abzuschneiden?

von Stephan S. (outsider)


Lesenswert?

Wolfgang Birner wrote:
> Gehts oder kannst du nicht vielleicht (1*x/(0,002*x)) = 500 rechnen? mit
> x = 1000 wärst du im reinen int-Bereich.

Das hab ich mir gestern auch schon gedacht und getestet, funktionierte 
aber nicht. Grad eben kam mir aber dann doch die Erleuchtung: selbst 
wenn ich 0,002 * 1000 rechne ists 2.0, also noch immer vom Typ float. 
Wenn man das dann nach einem int Typen castet läufts!

Bleibt nur noch die Frage ob es bei der Berechnung vom Produkt auch zu 
Fehlern kommt die dann wieder als Ergebnis z.B. 1.99999995 haben und 
dann das casten wieder schief läuft.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Lies mal im Link weiter unter "non-bugs"

http://gcc.gnu.org/bugs.html#known

von Michael Wilhelm (Gast)


Lesenswert?

Beim normalen int oder so:

var * 10;
var + 5;
var / 10;
fertig.

MW

von Simon K. (simon) Benutzerseite


Lesenswert?

Stephan S. wrote:
> Gibts nicht einfach eine Funktion die auf ganze Zahlen rundet wie man es
> gewohnt ist ohne einfach was abzuschneiden?

Klar gibts die. Sie steht drei Posts über dem von mir jetzt zitierten.

Beitrag "Re: 1/0.002 = 499 Wie krieg ich da 500 raus?"

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.