Toon posts:

[C++] Double trouble

Pagina: 1
Acties:

Verwijderd

Topicstarter
Een probleempje met een paar doubles. Het is echt supervaag en ik kom er absoluut niet uit.

Het volgende:
C++:
1
2
3
4
5
6
7
if ((2307.21 >= 2307.21 && 2307.21 <= 2307.25) || 
    (2307.21 >= 2307.25 && 2307.21 <= 2307.21)) {
    if ((281.219 >= 281.219 && 281.219 <= 281.272) || 
        (281.219 >= 281.272 && 281.219 <= 281.219)) {
      cout << "blaat" << endl;
    }
  }


Doet zijn werk prima en print netjes "blaat" op het scherm.

En deze:
C++:
1
2
3
4
5
6
7
8
double tx = 2307.21, ty = 281.219, x1 = 2307.21, y1 = 281.219;
double x2 = 2307.25, y2 = 281.272;

if ((tx >= x1 && tx <= x2) || (tx >= x2 && tx <= x1)) {
    if ((ty >= y1 && ty <= y2) || (ty >= y2 && ty <= y1)) {
      cout << "blaat" << endl;
    }
  }


Doet het ook prima en print netjes "blaat" op het scherm.

Maar wanneer ik deze doe:
C++:
1
2
3
4
5
6
7
8
9
double tx = trackPtr->x, ty = trackPtr->y;
double x1 = leafParents[0].x1, y1 = leafParents[0].y1;
double x2 = leafParents[0].x2, y2 = leafParents[0].y2;

if ((tx >= x1 && tx <= x2) || (tx >= x2 && tx <= x1)) {
    if ((ty >= y1 && ty <= y2) || (ty >= y2 && ty <= y1)) {
      cout << "blaat" << endl;
    }
  }


Gebeurt er helemaal niks. En de waarden die ik bij de laatste in de doubles stop zijn precies dezelfde als in de voorbeelden daarboven. Wanneer ik die met "cout" print zijn ze exact gelijk.

Is er iets met doubles in C++ wat ik blijkbaar niet weet :?

[ Voor 13% gewijzigd door Verwijderd op 04-04-2003 05:48 . Reden: layout verpest ]


Verwijderd

Probeer elke vergelijking apart uit te voeren en print uit of die succesvol afgerondt wordt, dan weet je welke vergelijking fout gaat. Dit is nogal gokwerk zo.

Ik gok dat in bovenstaande gevallen de compiler optimizet. Onderin lukt dat niet, omdat de waarden niet van tevoren bekend zijn, en dan moet ie dus afronden op getallen die in een double passen (een double is ook niet van oneindige precisie) en daar zal wel wat fout gaan... Da's het eerste wat in me opkomt.

Maargoed, nogmaals, per vergelijking even uitprinten. :).

  • whoami
  • Registratie: December 2000
  • Laatst online: 23:02
Idd, het zal te maken hebben met de afronding en de precisie.

Daarom doe vergelijk je best double of float variabelen op 'equality' op de volgende manier:

code:
1
2
3
4
5
6
7
8
9
10
11
12
const double verschil = 0.0000001;

if( Abs(double1 - double2) < verschil )
{

  cout << "gelijk";

}
else
{
  cout << "niet gelijk";
}

https://fgheysels.github.io/


  • BoAC
  • Registratie: Februari 2003
  • Laatst online: 22-08 21:48

BoAC

Memento mori

Ahh!! Heb ook wel problemen met doubles gehad:

Je mag nooit bij doubles checken op == dus ook niet op <= of >=!!
Dit omdat de laagst significante bit niet gedefinieerd is bij een double.

Heb hiermee problemen gehad bij het bouwen van een tekenprogramma waarbij afstandsberekeningen werden gedaan. Je kan dus beter !(X > 1.2345) dan (X <= 1.2345).

  • Soultaker
  • Registratie: September 2000
  • Laatst online: 22-08 01:56
BoAC schreef op 04 april 2003 @ 09:26:
Ahh!! Heb ook wel problemen met doubles gehad:

Je mag nooit bij doubles checken op == dus ook niet op <= of >=!!
Mag best, maar wees je er dan van bewust dat operaties op floating point getallen afrondingsfouten tot gevolg kunnen hebben, waardoor iets als (3.0 * 5.0 / 3.0) == (5.0) niet meer op zou kunnen gaan. Testen op gelijkheid is hierdoor bijna altijd onwenselijk, maar in het algemeen is er niet echt een probleem met >= en <=. Als je echter ook getallen die 'op de rand' liggen mee wil nemen, zul je een kleine marge moeten inbouwen.
Dit omdat de laagst significante bit niet gedefinieerd is bij een double.
Wel hoor! ;)
Heb hiermee problemen gehad bij het bouwen van een tekenprogramma waarbij afstandsberekeningen werden gedaan. Je kan dus beter !(X > 1.2345) dan (X <= 1.2345).
Wat je nu voorstelt is volledig equivalent aan elkaar. Als ik door afronding een getal heb dat net 1.23450001 is geworden, levert de expressie !(1.23450001 > 1.2345) net zo goed 0 op als (1.23450001 < = 1.2345). Een betere suggestie zou zijn om expliciet een marge te definieren; zoiets als dit dus: (X <= 1.2345000001). (Voor een geschikte marge moet je even checken hoeveel bits er in de mantissa van een double zitten en waar je de foutengrens wilt leggen). Zoals whoami al zij, dus.

Ik moet wel kwijt dat ik die marges ontzettend lelijk vind...

  • MSalters
  • Registratie: Juni 2001
  • Laatst online: 21-08 17:14
Die marges werken wel, maar niet zoals hier wordt voorgesteld als een additionele constante. Stel, je hebt een marge (epsilon) van 10-10, dan kun je dus niet serieus doubles vergelijken van 10-20 of 10[super]+20[/]. De truc is dat je de twee getallen moet delen, en dan kijken of het resultaat in de buurt van de 1 ligt. Dan kun je wel checken op 1-eps < ratio < 1+eps

Man hopes. Genius creates. Ralph Waldo Emerson
Never worry about theory as long as the machinery does what it's supposed to do. R. A. Heinlein


  • Soultaker
  • Registratie: September 2000
  • Laatst online: 22-08 01:56
Dat delen is wel slim! Ik gok zelf altijd een beetje op basis van het aantal bits in de mantissa en de orde van grootte waar de getallen in liggen, maar ik schrijf dan ook nooit applicaties die nauwkeurige berekeningen vereisen.

  • windancer
  • Registratie: Maart 2000
  • Laatst online: 18-08 22:36
Wel natuurlijk ff checken of je niet deelt door 0, of iets wat daar errug op lijkt. ;-)
MSalters schreef op 04 april 2003 @ 09:51:
Die marges werken wel, maar niet zoals hier wordt voorgesteld als een additionele constante. Stel, je hebt een marge (epsilon) van 10-10, dan kun je dus niet serieus doubles vergelijken van 10-20 of 10+20. De truc is dat je de twee getallen moet delen, en dan kijken of het resultaat in de buurt van de 1 ligt. Dan kun je wel checken op 1-eps < ratio < 1+eps

[ Voor 2% gewijzigd door windancer op 04-04-2003 18:52 . Reden: Probleem met quote ]


  • MSalters
  • Registratie: Juni 2001
  • Laatst online: 21-08 17:14
0 is met floating-point math een probleem. Is 0 gelijk aan 0.001? 0.0001? Daar moet je een domein-specifieke absolute epsilon kiezen.
offtopic:
windancer: fix die smiley en quote even

Man hopes. Genius creates. Ralph Waldo Emerson
Never worry about theory as long as the machinery does what it's supposed to do. R. A. Heinlein


  • Soultaker
  • Registratie: September 2000
  • Laatst online: 22-08 01:56
MSalters schreef op 04 april 2003 @ 18:37:
0 is met floating-point math een probleem. Is 0 gelijk aan 0.001? 0.0001? Daar moet je een domein-specifieke absolute epsilon kiezen.
offtopic:
windancer: fix die smiley en quote even
Als je dicht bij de 'grens' van de float waarde wil gaan zitten moet je sowieso je marge kleiner kiezen als je dichter bij nul komt, omdat de waarden dan gedenormaliseerd opgeslagen gaan worden. Maar goed, dat is wel ontzettende mierenneukerij.

[ Voor 4% gewijzigd door Soultaker op 04-04-2003 20:09 ]


Verwijderd

Topicstarter
Hier had ik dus nog niet aan gedacht. Klinkt allemaal erg logisch. Tnx _/-\o_

Sorry dat ik zo laat pas weer reageer, in het weekend kan ik hier niet internetten.

Verwijderd

Topicstarter
Ik weet nu wel een oplossing, maar toch wel vreemd het verschil tussen het tweede en derde voorbeeld dat ik noem in mijn openingspost.

Want de variabelen aan de rechterkant in het derde voorbeeld zijn ook gewoon het resultaat van een simpele assignment als in voorbeeld nummer twee.

Verwijderd

Uhm, als je 'n waarde output hoeft dat niet met volledige precisie te zijn..

Kan me voorstellen dat je waarde's net iets anders zijn dan wat er geprint wordt.

(Zelfde als in je debugger-window in VC - daar worden waardes van floats / doubles ook getruncate)

Verwijderd

Topicstarter
Verwijderd schreef op 07 April 2003 @ 11:28:
Uhm, als je 'n waarde output hoeft dat niet met volledige precisie te zijn..

Kan me voorstellen dat je waarde's net iets anders zijn dan wat er geprint wordt.

(Zelfde als in je debugger-window in VC - daar worden waardes van floats / doubles ook getruncate)
Dat snap ik, maar de waardes worden eerst uit een file ingelezen en in die file staat bijvoorbeeld 2307.211 gewoon als 2307.211 en is de assignment dus ook gewoon iets als 'double x = 2307.211'. Dus ik snap niet helemaal hoe die waarde in de variabele dan toch weer afwijkt van wat er in de file staat.

[ Voor 5% gewijzigd door Verwijderd op 08-04-2003 00:41 ]

Pagina: 1