ungenauigkeit bei float Berechnung
-
Hallo,
bei mir geht es um eine ganz einfache Funktion. Zwei float Variablen (walkX, walkZ) werden in jedem Zeitschritt um walkVelocity (= 0.1) verringert. Desweiteren soll das ganze nur laufen wenn walkX oder walkZ ungleich null sind.
Code:if ((walkX != 0) || (walkZ != 0)){ //as long as there is some way to walk if (walkX > 0){ walkX -= walkVelocity; position.x += walkVelocity; } if (walkX < 0){ walkX += walkVelocity; position.x -= walkVelocity; } if (walkZ > 0){ walkZ -= walkVelocity; position.z += walkVelocity; } if (walkZ < 0){ walkZ += walkVelocity; position.z -= walkVelocity; } }Lasse ich mir das ganze für eine Vairable ausgeben ergibt sich folgendes z.B. von 1.1 ausgehend:
1.1
1.0
0.9000002
0.8000002
.
.
.
1.56462e-006Wieso wird das ganze nun nicht genau Null?
Vielleicht stehe ich ja auch komplett auf dem Schlauch, würde mich freuen wenn mir jemand helfen könnte.
viele Grüße
Smiffi
-
Hi !
Initialisierung ?
walkX = 2**.6**;
walkZ = 3**.0**;
-
Ist technisch bedingt, mach am besten selbst 'ne Abfrage ob die Zahl in 'nem kleinen Bereich kleiner Null und größer Null ist.
-
Es ist so weil float/double keine GENAUE Speicherung einer reelen Zahl können sondern nur eine Aproximative.
Warum benutzt ihr eigendlich immer Datentypen ohne euch vorher mal darüber zu informieren? Es dauert genau 30 Sekunden um die Information ueber float im wiki zu finden:
http://de.wikipedia.org/wiki/Gleitkommazahl
Aber lesen ist halt nicht mehr Jedermanns sache...
-
Smiffi schrieb:
Wieso wird das ganze nun nicht genau Null?
weil nach der gängigen Art und Weise Fließkommazahlen binär darzustellen, der Wert 0,1 nur näherungsweise berechnet werden kann.
Die Lösung besteht in solchen Fällen darin, die Zeitschritte über eine Integer Variable zu zählen und die neue Zeit aus dem Integer zu berechnen. Etwa so
float walk = 2.0; int iZeitschritt = 0; // in der Schleife for( ; ; ++iZeitschritt ) Zeitschritte zählen float walkX = walk - iZeitschritt * 0.1;Trotzdem ist nicht garantiert, dass eine Abfrage von walkX auf 0.0 irgendwann erfolgreich sein wird. Grundsätzlich sollte man keine float oder double mit == vergleichen, sondern nur über Toleranzen. In diesem Fall ist es vielleicht eher angebracht, die Anzahl der Zeitschritte vorher zu bestimmen.
Gruß
Werner
-
loks schrieb:
Aber lesen ist halt nicht mehr Jedermanns sache...
man muss vorher ja erst drauf kommen, dass solch ein Problem überhaupt existiert. Der unbedarfte Anfänger tut das sicher nicht.
Ich für meinen Teil habe mich auch noch nie darüber informiert, ob man beim Runterzählen einer positiven Integer Variablen immer irgendwann sicher bei 0 landet.Gruß
Werner
-
loks schrieb:
Es ist so weil float/double keine GENAUE Speicherung einer reelen Zahl können sondern nur eine Aproximative.
Warum benutzt ihr eigendlich immer Datentypen ohne euch vorher mal darüber zu informieren? Es dauert genau 30 Sekunden um die Information ueber float im wiki zu finden:
Und warum benutzt Du Worte (und setzt sie auch noch in fett) ohne Dich zuvor über deren Schreibweise zu informieren? -- Approximativ schreibt man mit zwei p. Das rauszufinden kostet einen doch höchstens 30 Sekunden.
Aber lesen ist halt nicht mehr Jedermanns sache...
SCNR

-
Genau, was im dezimalen 1/3 ist, ist im binären die 0.1 ist also ohne Rest nicht teilbar, deshalb landet man nicht bei Null.
Wenn man für im binären teilbare Intervalle sorgt( 0.125, 0.0625 ) und dafür sorgt das walkX und walkZ ein Vielfaches davon sind, dann klappt das.#include <stdio.h> #include <windows.h> int main() { float walkVelocity = 0.125 ; float walkX = -20 * walkVelocity, walkZ = 30 * walkVelocity; while (( walkX != 0.0 ) || ( walkZ != 0.0 )) { if (walkX > 0) walkX -= walkVelocity; if (walkX < 0) walkX += walkVelocity; if (walkZ > 0) walkZ -= walkVelocity; if (walkZ < 0) walkZ += walkVelocity; printf("\r %f %f", walkX, walkZ ); Sleep(400); } return 0; }
-
Wie schon gesagt wurde ist es für einen Anfänger manchmal nicht so einfach, zu erkennen ob solche Probleme überhaupt existieren. Aber nun bin ich ja schlaucher

viele Grüße