JLI Spieleprogrammierung Foren-Übersicht JLI Spieleprogrammierung

 
 FAQFAQ   SuchenSuchen   MitgliederlisteMitgliederliste   BenutzergruppenBenutzergruppen 
 medals.php?sid=2de71972c0deedac927b817028ffc9c1Medaillen   RegistrierenRegistrieren   ProfilProfil   Einloggen, um private Nachrichten zu lesenEinloggen, um private Nachrichten zu lesen   LoginLogin 

float/double Ungenauigkeit, Trick gesucht
Gehe zu Seite 1, 2  Weiter
 
Neues Thema eröffnen   Neue Antwort erstellen    JLI Spieleprogrammierung Foren-Übersicht -> Entwicklung
Vorheriges Thema anzeigen :: Nächstes Thema anzeigen  
Autor Nachricht
DirectXer
Dark JLI'ler



Anmeldedatum: 05.02.2005
Beiträge: 1201
Wohnort: Köln
Medaillen: Keine

BeitragVerfasst am: 11.05.2006, 18:52    Titel: float/double Ungenauigkeit, Trick gesucht Antworten mit Zitat

Hi Volkz!

Ich schreibe grad ein Programm was Gleichungssysteme nach Gauß usw. löst; hab nur ein kleines Problem: Ihr kennt ja sicher den float/double Toleranzbereich und die Ungenauigkeit, wie z.B. hier:
CPP:
float f = 4.0f;
f *= 0.25f; // für f /= 4.0f;
schade, da ist dummerweise f != 1, sondern 1,0000000002 oder 0,99999999998 oder so ähnlich. Nur nützen diese halb genauen Ergebnisse dem Benutzer nichts, er will net wissen was X ungefähr ist, sondern was X genau ist. Was kann man da machen? Gibts irgendwelche besonderen Tricks?

Gruß DXer
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden E-Mail senden
Fallen
JLI MVP
JLI MVP


Alter: 40
Anmeldedatum: 08.03.2003
Beiträge: 2860
Wohnort: Münster
Medaillen: 1 (mehr...)

BeitragVerfasst am: 11.05.2006, 18:59    Titel: Antworten mit Zitat

Suche mal unter goofle nach apfloat, das ist eine lib für extrem genaue zahlenbereiche (par tausende nachkommastellen AFAIK ist dein Speicher der Grenzgeber)

Ansonsten kannst du natürlich auch versuchen mit ganzzahlen zu rechnen und bei der Ausgabe das ganze zurecht formatieren.
_________________
"I have a Core2Quad at 3.2GHz, 4GB of RAM at 1066 and an Nvidia 8800 GTS 512 on Vista64 and this game runs like ass whereas everything else I own runs like melted butter over a smokin' hot 18 year old catholic schoolgirl's arse."
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden E-Mail senden Website dieses Benutzers besuchen
Jonathan_Klein
Living Legend


Alter: 37
Anmeldedatum: 17.02.2003
Beiträge: 3433
Wohnort: Siegerland
Medaillen: Keine

BeitragVerfasst am: 11.05.2006, 19:09    Titel: Antworten mit Zitat

Ich wäre einfach dafür das du auf 10 Stellen oder so rundest, und dann mit if abcheckst ob das Ergebnis stimmt. Ich glaube selbst wenn du 1000 Stellen hättest wäre das Ergebnis warhshceinlich noch um 1/10^1000 falsch, daher würde das auch nicht sehr viel weiter helfen.
Unser Taschenrechner hat auch imemr so Ergebnisse, und bei den meisten Aufgaben kommt nix mit mehr als 10 Nachkommastellen raus, und wenn doch ist es wahrschienlich was im Naturwissenschaftlichen Bereich, wo sowieso niemal irgendetwas genau ist.
_________________
https://jonathank.de/games/
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden E-Mail senden Website dieses Benutzers besuchen
GreveN
JLI Master


Alter: 37
Anmeldedatum: 08.01.2004
Beiträge: 901
Wohnort: Sachsen - Dresden
Medaillen: Keine

BeitragVerfasst am: 11.05.2006, 19:37    Titel: Antworten mit Zitat

Dafür kann man sich ja z.B. ein Epsilon-Umgebung definieren und dann immer testen, ob das Ergebnis im Intervall Zielergebnis +- Epsilon liegt..

CPP:
template<typename T>
struct epsilon { static const T value; };

template<>
const float  epsilon<float> ::value = 0.00001f;

template<>
const double epsilon<double>::value = 0.0000001;


Edit: Ungünstige Formulierung verbessert.


Zuletzt bearbeitet von GreveN am 13.05.2006, 09:02, insgesamt einmal bearbeitet
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden Yahoo Messenger MSN Messenger
PeaceKiller
JLI Master


Alter: 35
Anmeldedatum: 28.11.2002
Beiträge: 970

Medaillen: Keine

BeitragVerfasst am: 11.05.2006, 21:15    Titel: Antworten mit Zitat

Der Trick den professionelle CAS-Programme verwenden ist, dass sie das Ergebniss nicht ausrechnen, sondern als Bruch behalten. Das wird halt ziemlich aufwendig.
_________________
»If the automobile had followed the same development cycle as the computer, a Rolls-Royce would today cost $100, get a million miles per gallon, and explode once a year, killing everyone inside.«
– Robert X. Cringely, InfoWorld magazine
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden Website dieses Benutzers besuchen
AFE-GmdG
JLI MVP
JLI MVP


Alter: 45
Anmeldedatum: 19.07.2002
Beiträge: 1374
Wohnort: Irgendwo im Universum...
Medaillen: Keine

BeitragVerfasst am: 11.05.2006, 22:38    Titel: Antworten mit Zitat

Wenn es nicht unbedingt c++ sein muss, könntest du auch c# benutzen, dort gibt es neben float / double noch den Variablentyp decimal. Der rechnet mit Festkomma (ich glaub so um die 60 Stellen nach dem Komma)
Rundungsfehler, wie du sie oben beschreibst treten mit diesem Typ nicht auf.
_________________
CPP:
float o=0.075,h=1.5,T,r,O,l,I;int _,L=80,s=3200;main(){for(;s%L||
(h-=o,T= -2),s;4 -(r=O*O)<(l=I*I)|++ _==L&&write(1,(--s%L?_<(L)?--_
%6:6:7)+\"World! \\n\",1)&&(O=I=l=_=r=0,T+=o /2))O=I*2*O+h,I=l+T-r;}
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden E-Mail senden Website dieses Benutzers besuchen
DirectXer
Dark JLI'ler



Anmeldedatum: 05.02.2005
Beiträge: 1201
Wohnort: Köln
Medaillen: Keine

BeitragVerfasst am: 12.05.2006, 18:30    Titel: Antworten mit Zitat

@GreveN, Jona und Fallen:

von allen Möglichkeiten spricht mich die lib von Fallen am meisten an, ich werd da mal was suchen


@Peacekiller

ich mache das u.A. auch, ich hab eine Bruchklasse, aber die WinAPI-Funktionen usw. machen das net so, deshalb bin ich darauf angewiesen; weshalb die lib von Fallen da auch geeignet ist


@AFE-GmdG

ne, muss c++ sein Razz


Gruß DXer
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden E-Mail senden
KI
JLI Master


Alter: 39
Anmeldedatum: 04.07.2003
Beiträge: 965
Wohnort: Aachen
Medaillen: Keine

BeitragVerfasst am: 12.05.2006, 20:03    Titel: Antworten mit Zitat

Aus meiner Erfahrung sollte man float-Variablen nie auf Gleichheit prüfen, weil die eine eben den Wert 0.0099999998 haben kann und die andere 0.0100000001. Das liegt an der Darstellung von floats im System.
Da 0.01 nur durch unendlich viele Dualbrüche (Binärbruche) dargestellt werden kann, erhält man immer nur eine Näherung des Wertes. Aber nie exakt 0.01.

Ich hab genau deswegen mal einen Funktion gemacht.
fTest und fBase sind die beiden zu vergleichenden Werte und mit fTolerance gibt man den Toleranzbereich an, in dem die zwei Zahlen liegen sollen.
CPP:
bool isAround(float fTest, float fBase, float fTolerance)
{
   if(fTest == fBase)
      return true;

   if(fTest < fBase + fTolerance && fTest > fBase - fTolerance)
      return true;

   return false;
}

Das ist z.B auch praktisch in einem Beat 'em Up Spiel um zu gucken, ob er Gegner in Schlagdistanz liegt. Wink Da sollte man dann einen größeren Toleranzbereich angeben.
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden E-Mail senden
GreveN
JLI Master


Alter: 37
Anmeldedatum: 08.01.2004
Beiträge: 901
Wohnort: Sachsen - Dresden
Medaillen: Keine

BeitragVerfasst am: 12.05.2006, 21:12    Titel: Antworten mit Zitat

Das ist ja im Grunde das, was ich schon vorgeschlagen hatte, mit einem Grenzwert. Razz

Edit: Ich seh grade, ich habe das etwas doof formuliert in meinem ersten Post, man testet natürlich nicht auf Gleichheit, sondern ob das Ergebnis in dem Intervall [Zielergebnis - Epsilon; Zielergebnis + Epsilon] liegt.
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden Yahoo Messenger MSN Messenger
DirectXer
Dark JLI'ler



Anmeldedatum: 05.02.2005
Beiträge: 1201
Wohnort: Köln
Medaillen: Keine

BeitragVerfasst am: 13.05.2006, 15:54    Titel: Antworten mit Zitat

hmm, es gibt grad einige (leicht zu behebende) Probleme mit der lib. Während dem Doku-Studieren bin ich auf folgende Idee gekommen: Kann ich net einfach mit strings anstatt mit floats/doubles rechnen? Fallen hatte das mal angedeutet, kannst du mir das mal an nem Beispiel zeigen? Ich hab schon ne kleine Vorstellung; aber da Fallen das AFAIK schon mal gemacht hat, ist es gut, wenn ich mir die Ansätze bei ihm hole Wink (jeder andere, der auch Ahnung davon hat, her damit Cool )

Gruß DXer
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden E-Mail senden
Fallen
JLI MVP
JLI MVP


Alter: 40
Anmeldedatum: 08.03.2003
Beiträge: 2860
Wohnort: Münster
Medaillen: 1 (mehr...)

BeitragVerfasst am: 13.05.2006, 19:17    Titel: Antworten mit Zitat

Mit Strings rechnen/arbeitem würde ich sein lassen, damit ein gutes System zu erarbeiten kann ziemlich hart werden. daher nehme lieber eine fertige lib so wie zB apfloat.

Hier mal ein Beispiel für die Berechnung von PI, in 30min hatte er bei mir 4.999.987 Nachkommastellen.

www.dragonfx.de/download/APFloat.rar
_________________
"I have a Core2Quad at 3.2GHz, 4GB of RAM at 1066 and an Nvidia 8800 GTS 512 on Vista64 and this game runs like ass whereas everything else I own runs like melted butter over a smokin' hot 18 year old catholic schoolgirl's arse."
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden E-Mail senden Website dieses Benutzers besuchen
DirectXer
Dark JLI'ler



Anmeldedatum: 05.02.2005
Beiträge: 1201
Wohnort: Köln
Medaillen: Keine

BeitragVerfasst am: 13.05.2006, 19:25    Titel: Antworten mit Zitat

Fallen hat Folgendes geschrieben:
Mit Strings rechnen/arbeitem würde ich sein lassen, damit ein gutes System zu erarbeiten kann ziemlich hart werden. daher nehme lieber eine fertige lib so wie zB apfloat.

Hier mal ein Beispiel für die Berechnung von PI, in 30min hatte er bei mir 4.999.987 Nachkommastellen.

www.dragonfx.de/download/APFloat.rar

das mit der lib hab ich ja schon, aber da gibts auch so probleme:
apfloat/readme+FAQ hat Folgendes geschrieben:
CPP:
int main(int argc, char *argv[])
{
    apfloat a = 2.0,
            b = 1.0,
            c = 0.5,
            d = 1e-13;

    cout << pretty << a << endl;
    cout << pretty << b << endl;
    cout << pretty << c << endl;
    cout << pretty << d << endl;

    return 0;
}


You might get an output like:
Code:
2
1
0.500000000000000059
0.000000000000100000000000000014551915


In fact, any of the three first lines output can be "incorrect", and the last line output is almost certainly "incorrect".


naja, da steht auch, dass man das Problem beheben kann, indem man mit strings rechnet: (allerdings mit deren System)
apfloat/readme+FAQ hat Folgendes geschrieben:
The obvious workaround is to use the constructor taking a string, which guarantees that the digits your number will have are exactly the same ones that you specify. For example:


apfloat x("0.5", 1000);


Gruß DXer
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden E-Mail senden
GreveN
JLI Master


Alter: 37
Anmeldedatum: 08.01.2004
Beiträge: 901
Wohnort: Sachsen - Dresden
Medaillen: Keine

BeitragVerfasst am: 13.05.2006, 20:06    Titel: Antworten mit Zitat

Öhm, das klingt sehr umständlich wie du das lösen willst, warum schreibst' dir nicht einfach eine Funktion die dir die Funktionalität des '==-Operators' für floats ersetzt? Ich mein, letztendlich ist es deine Entscheidung, aber bevor ich mein Projekt mit einer Extra-Lib aufblähe oder irgendeinen komplizierten, halsbrecherischen Algorithmus implementiere... schau dir das doch bitte nochmal an (ist im Prinzip dasselbe wie von KI):
CPP:
//****************************************************************
//** interval
//****************************************************************
template<typename T>
inline const bool interval(const T& value, const T& min, const T& max)
{ return ((value<=max) && (value>=min)); }


//****************************************************************
//** is_equal
//****************************************************************
template<typename T>
inline const bool is_equal(const T& a, const T& b)
{ return (a==b); }

template<>
inline const bool is_equal<float>(const float& a, const float& b)
{ return interval(a, (b-epsilon<float>::value), (b+epsilon<float>::value)); }

template<>
inline const bool is_equal<double>(const double& a, const double& b)
{ return interval(a, (b-epsilon<double>::value), (b+epsilon<double>::value)); }


Find ich persönlich eigentlich sehr smart. Cool Und genügt für jeden mir bekannten Fall. Cool

Aber letztendlich deine Entscheidung, kann ja sein, dass du diese derbst hohe Genauigkeit wirklich brauchst...
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden Yahoo Messenger MSN Messenger
DirectXer
Dark JLI'ler



Anmeldedatum: 05.02.2005
Beiträge: 1201
Wohnort: Köln
Medaillen: Keine

BeitragVerfasst am: 13.05.2006, 20:31    Titel: Antworten mit Zitat

GreveN hat Folgendes geschrieben:

Aber letztendlich deine Entscheidung, kann ja sein, dass du diese derbst hohe Genauigkeit wirklich brauchst...

jo die brauch ich. Es geht aber net ums vergleichen. Ließ dir meinen 1. Post nochma durch, was ich bezwecken will. Razz Arrow Wenn der User z.B. das eingibt:
Code:

2X = Y;
Y = 4;

möchte der User garantiert net so ein Ergebnis bekommen:
Code:

X = 1.999999999999998;
Y = 4.000000000000001;


Gruß DXer

EDIT: Ich brauche die Lib aber auch noch für andere sachen, also sie wären nützlich. Deshalb verzichte ich auf runden. Das mit den Strings war allerdings sehr interessant...
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden E-Mail senden
GreveN
JLI Master


Alter: 37
Anmeldedatum: 08.01.2004
Beiträge: 901
Wohnort: Sachsen - Dresden
Medaillen: Keine

BeitragVerfasst am: 13.05.2006, 20:54    Titel: Re: float/double Ungenauigkeit, Trick gesucht Antworten mit Zitat

DirectXer hat Folgendes geschrieben:
Nur nützen diese halb genauen Ergebnisse dem Benutzer nichts, er will net wissen was X ungefähr ist, sondern was X genau ist. Was kann man da machen? Gibts irgendwelche besonderen Tricks?

Mein Taschenrechner (Ti83plus) rechnet selbst an Graphen "nur" mit Näherungswerten herum... Ergebnisse wie 4,9999999999 sind da gang und gebe und eigentlich niemand käme auf den Gedanken, dass nicht als 5 zuverstehen, soviel Intelligenz kann man einem Nutzer, der zugegebnermaßen ja auch weiß was er da tut und zu erwarten hat, schon abverlangen behaupte ich mal, zumal das ja alles andere als "halbgenau" ist... Also zieht das Argument nicht so ganz..., und wenn du die Zahl auf 10 Stellen oder so rundest (mein Gott, wo braucht man schon mehr wie 10 Stellen Genauigkeit bei Endergebnissen?) ist der Wert auch schon wieder glatt...
Und "Tricks" wurden hier ja einige gezeigt...
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden Yahoo Messenger MSN Messenger
Beiträge der letzten Zeit anzeigen:   
Neues Thema eröffnen   Neue Antwort erstellen    JLI Spieleprogrammierung Foren-Übersicht -> Entwicklung Alle Zeiten sind GMT
Gehe zu Seite 1, 2  Weiter
Seite 1 von 2

 
Gehe zu:  
Du kannst keine Beiträge in dieses Forum schreiben.
Du kannst auf Beiträge in diesem Forum nicht antworten.
Du kannst deine Beiträge in diesem Forum nicht bearbeiten.
Du kannst deine Beiträge in diesem Forum nicht löschen.
Du kannst an Umfragen in diesem Forum nicht mitmachen.


Powered by phpBB © 2001, 2005 phpBB Group
Deutsche Übersetzung von phpBB.de

Impressum