www.mikrocontroller.net

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


Autor: Stephan S. (outsider)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Lothar Miller (lkmiller) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Freizeitbastler (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Braten (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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 :-)

Autor: Stephan S. (outsider)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Simon K. (simon) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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:
unsigned long Round(double Value)
{
    if (Value < 0)
        return (unsigned long) (Value - 0.5)
    else
        return (unsigned long) (Value + 0.5)
}

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

Autor: bohner (Gast)
Datum:

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

Autor: Wolfgang Birner (logox2)
Datum:

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

Autor: Stephan S. (outsider)
Datum:

Bewertung
0 lesenswert
nicht 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?

Autor: Stephan S. (outsider)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Johann L. (gjlayde) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Lies mal im Link weiter unter "non-bugs"

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

Autor: Michael Wilhelm (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Beim normalen int oder so:

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

MW

Autor: Simon K. (simon) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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?"

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.