|
JLI Spieleprogrammierung
|
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
|
Verfasst am: 11.05.2006, 18:52 Titel: float/double Ungenauigkeit, Trick gesucht |
|
|
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 |
|
|
Fallen JLI MVP
Alter: 40 Anmeldedatum: 08.03.2003 Beiträge: 2860 Wohnort: Münster Medaillen: 1 (mehr...)
|
Verfasst am: 11.05.2006, 18:59 Titel: |
|
|
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 |
|
|
Jonathan_Klein Living Legend
Alter: 37 Anmeldedatum: 17.02.2003 Beiträge: 3433 Wohnort: Siegerland Medaillen: Keine
|
Verfasst am: 11.05.2006, 19:09 Titel: |
|
|
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 |
|
|
GreveN JLI Master
Alter: 37 Anmeldedatum: 08.01.2004 Beiträge: 901 Wohnort: Sachsen - Dresden Medaillen: Keine
|
Verfasst am: 11.05.2006, 19:37 Titel: |
|
|
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 |
|
|
PeaceKiller JLI Master
Alter: 35 Anmeldedatum: 28.11.2002 Beiträge: 970
Medaillen: Keine
|
Verfasst am: 11.05.2006, 21:15 Titel: |
|
|
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 |
|
|
AFE-GmdG JLI MVP
Alter: 45 Anmeldedatum: 19.07.2002 Beiträge: 1374 Wohnort: Irgendwo im Universum... Medaillen: Keine
|
Verfasst am: 11.05.2006, 22:38 Titel: |
|
|
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 |
|
|
DirectXer Dark JLI'ler
Anmeldedatum: 05.02.2005 Beiträge: 1201 Wohnort: Köln Medaillen: Keine
|
Verfasst am: 12.05.2006, 18:30 Titel: |
|
|
@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
Gruß DXer |
|
Nach oben |
|
|
KI JLI Master
Alter: 39 Anmeldedatum: 04.07.2003 Beiträge: 965 Wohnort: Aachen Medaillen: Keine
|
Verfasst am: 12.05.2006, 20:03 Titel: |
|
|
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. Da sollte man dann einen größeren Toleranzbereich angeben. |
|
Nach oben |
|
|
GreveN JLI Master
Alter: 37 Anmeldedatum: 08.01.2004 Beiträge: 901 Wohnort: Sachsen - Dresden Medaillen: Keine
|
Verfasst am: 12.05.2006, 21:12 Titel: |
|
|
Das ist ja im Grunde das, was ich schon vorgeschlagen hatte, mit einem Grenzwert.
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 |
|
|
DirectXer Dark JLI'ler
Anmeldedatum: 05.02.2005 Beiträge: 1201 Wohnort: Köln Medaillen: Keine
|
Verfasst am: 13.05.2006, 15:54 Titel: |
|
|
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 (jeder andere, der auch Ahnung davon hat, her damit )
Gruß DXer |
|
Nach oben |
|
|
Fallen JLI MVP
Alter: 40 Anmeldedatum: 08.03.2003 Beiträge: 2860 Wohnort: Münster Medaillen: 1 (mehr...)
|
Verfasst am: 13.05.2006, 19:17 Titel: |
|
|
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 |
|
|
DirectXer Dark JLI'ler
Anmeldedatum: 05.02.2005 Beiträge: 1201 Wohnort: Köln Medaillen: Keine
|
Verfasst am: 13.05.2006, 19:25 Titel: |
|
|
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 |
|
|
GreveN JLI Master
Alter: 37 Anmeldedatum: 08.01.2004 Beiträge: 901 Wohnort: Sachsen - Dresden Medaillen: Keine
|
Verfasst am: 13.05.2006, 20:06 Titel: |
|
|
Ö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. Und genügt für jeden mir bekannten Fall.
Aber letztendlich deine Entscheidung, kann ja sein, dass du diese derbst hohe Genauigkeit wirklich brauchst... |
|
Nach oben |
|
|
DirectXer Dark JLI'ler
Anmeldedatum: 05.02.2005 Beiträge: 1201 Wohnort: Köln Medaillen: Keine
|
Verfasst am: 13.05.2006, 20:31 Titel: |
|
|
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. Wenn der User z.B. das eingibt:
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 |
|
|
GreveN JLI Master
Alter: 37 Anmeldedatum: 08.01.2004 Beiträge: 901 Wohnort: Sachsen - Dresden Medaillen: Keine
|
Verfasst am: 13.05.2006, 20:54 Titel: Re: float/double Ungenauigkeit, Trick gesucht |
|
|
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 |
|
|
|
|
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
|