I hate floating point operations
-
<Using MFC>
double dValue = atof("0.1"); ASSERT(dValue == 0.1); double dSecondValue = (1 + dValue + dValue + dValue + dValue); ASSERT(dSecondValue == 1.4); // Crash
Where do you expect us to go when the bombs fall?
A) Never hate B) Don't expect them to do what they can't
-
<Using MFC>
double dValue = atof("0.1"); ASSERT(dValue == 0.1); double dSecondValue = (1 + dValue + dValue + dValue + dValue); ASSERT(dSecondValue == 1.4); // Crash
Where do you expect us to go when the bombs fall?
I tried using the CRT assert instead and the same results occur. What's really surprising is the loss of precision when dSecondValue is evaluated. The second ASSERT is evaluating a compare between 1.4000000000000004 and 1.3999999999999999. But meanwhile dValue holds 0.10000000000000001. You do realize though that the first assert while being true, isn't comparing 0.1 to 0.1? Also when the number is less than 1 but greater than zero, you have seventeen digits of precision, but as soon as the value goes greater than 1, you only have sixteen digits of precision, following the decimal. It's odd that the digit four appears at the very end, cause it should have been truncated, I'd expect. Whether it's the use of assert, any comparisons using floating points are going to be subject to the oddities of float conversions to binary representations. They are good thing to avoid, if you can. :)
Chris Meech I am Canadian. [heard in a local bar] I agree with you that my argument is useless. [Red Stateler] Hey, I am part of a special bread, we are called smart people [Captain See Sharp] The zen of the soapbox is hard to attain...[Jörgen Sigvardsson] I wish I could remember what it was like to only have a short term memory.[David Kentley]
-
I tried using the CRT assert instead and the same results occur. What's really surprising is the loss of precision when dSecondValue is evaluated. The second ASSERT is evaluating a compare between 1.4000000000000004 and 1.3999999999999999. But meanwhile dValue holds 0.10000000000000001. You do realize though that the first assert while being true, isn't comparing 0.1 to 0.1? Also when the number is less than 1 but greater than zero, you have seventeen digits of precision, but as soon as the value goes greater than 1, you only have sixteen digits of precision, following the decimal. It's odd that the digit four appears at the very end, cause it should have been truncated, I'd expect. Whether it's the use of assert, any comparisons using floating points are going to be subject to the oddities of float conversions to binary representations. They are good thing to avoid, if you can. :)
Chris Meech I am Canadian. [heard in a local bar] I agree with you that my argument is useless. [Red Stateler] Hey, I am part of a special bread, we are called smart people [Captain See Sharp] The zen of the soapbox is hard to attain...[Jörgen Sigvardsson] I wish I could remember what it was like to only have a short term memory.[David Kentley]
Chris Meech wrote:
. You do realize though that the first assert while being true, isn't comparing 0.1 to 0.1?
Yep. Funny, isn't it?
Chris Meech wrote:
They are good thing to avoid, if you can.
Sometimes, you cannot choose what you do inherit :sigh: I would add, avoid atof. All the troubles come from it :mad:
Where do you expect us to go when the bombs fall?
-
<Using MFC>
double dValue = atof("0.1"); ASSERT(dValue == 0.1); double dSecondValue = (1 + dValue + dValue + dValue + dValue); ASSERT(dSecondValue == 1.4); // Crash
Where do you expect us to go when the bombs fall?
Never use
==
when comparing floating point numbers. Instead use subtraction and compare the result against a threshold value.double Threshold = 0.00000001;
double dSecondValue = 1 + dValue + dValue + dValue + dValue;
ASSERT(fabs(dSecondValue - 1.4) < Threshold);Last modified: 2mins after originally posted -- be sure to use the absolute value - negatives do not work.
You may be right I may be crazy -- Billy Joel -- Within you lies the power for good, use it!!!
-
<Using MFC>
double dValue = atof("0.1"); ASSERT(dValue == 0.1); double dSecondValue = (1 + dValue + dValue + dValue + dValue); ASSERT(dSecondValue == 1.4); // Crash
Where do you expect us to go when the bombs fall?
Anyone who dares to equality-compare floating point values with literals probably doesn't have a understanding of basic computer architecture. :) /ravi
-
<Using MFC>
double dValue = atof("0.1"); ASSERT(dValue == 0.1); double dSecondValue = (1 + dValue + dValue + dValue + dValue); ASSERT(dSecondValue == 1.4); // Crash
Where do you expect us to go when the bombs fall?
Maybe there should be "rookie mistakes" forum in here.
-
Anyone who dares to equality-compare floating point values with literals probably doesn't have a understanding of basic computer architecture. :) /ravi
I may have oversimplified. The case was more like the following: double dTime = 0.; double dT = atof(<some value read in a file>); double dFinal = atof(<some value read in a file>); do{ ... dTime += dT; ... while(dTime < dFinal); A loop was missing because of the 'epsilon' induced by atof.
Where do you expect us to go when the bombs fall?
-
Maybe there should be "rookie mistakes" forum in here.
-
<Using MFC>
double dValue = atof("0.1"); ASSERT(dValue == 0.1); double dSecondValue = (1 + dValue + dValue + dValue + dValue); ASSERT(dSecondValue == 1.4); // Crash
Where do you expect us to go when the bombs fall?
I really do think the compiler should throw an error when you try to compare floating point values for equality.
cheers, Chris Maunder
CodeProject.com : C++ MVP
-
With yours it makes then two of them.
Where do you expect us to go when the bombs fall?
At least three actually. Hmmmm... four... Incomplete, in no particular order, and without admitting to which ones I've committed. General: 1) Trying to swap two values without an intermediary 2) Not realizing the limitations of floating-point numbers 3) Various ways of introducing infinite loops 3a) Including infinite recursion 3a1) Especially with properties 4) Tests which either always pass or always fail In C languages: 1) Accidently using assignment in a test 2) Accidently falling-through in switches (not in C#) In SQL: 1) Not understanding implicit conversions 2) Naming tables, columns, etc. with reserved words, and not knowing about [] (if available)
-
<Using MFC>
double dValue = atof("0.1"); ASSERT(dValue == 0.1); double dSecondValue = (1 + dValue + dValue + dValue + dValue); ASSERT(dSecondValue == 1.4); // Crash
Where do you expect us to go when the bombs fall?
In VS2003 the float.h header has the following definitions :
#define DBL_EPSILON 2.2204460492503131e-016 /* smallest such that 1.0+DBL_EPSILON != 1.0 */
This is a very handy value to use when comparing floating point values. A tactic similar to this can be used :double value = ComputeValue(); double delta = fabs( value - expectedValue ); if( delta <= DBL_EPSILON ) TRACE( "values are considered to be equal\n" );
-
In VS2003 the float.h header has the following definitions :
#define DBL_EPSILON 2.2204460492503131e-016 /* smallest such that 1.0+DBL_EPSILON != 1.0 */
This is a very handy value to use when comparing floating point values. A tactic similar to this can be used :double value = ComputeValue(); double delta = fabs( value - expectedValue ); if( delta <= DBL_EPSILON ) TRACE( "values are considered to be equal\n" );
Rick York wrote:
if( delta <= DBL_EPSILON )
This is still not foolproof, as the floating point round-off errors can accumulate, depending on your calculations. If there is enough error in your calculations (try using log() or tan() near their "blow up" values, if you want really bad results, really quickly) then DBL_EPSILON will not be sufficient. Unfortunately (having seen this problem in action for many years) there is no one-line solution to this problem. The proper comparison will depend on your calculations, the input values, and what you are using your results for.
www.IconsReview.com <-- Huge list of stock icon collections (both free and commercial)
-
Rick York wrote:
if( delta <= DBL_EPSILON )
This is still not foolproof, as the floating point round-off errors can accumulate, depending on your calculations. If there is enough error in your calculations (try using log() or tan() near their "blow up" values, if you want really bad results, really quickly) then DBL_EPSILON will not be sufficient. Unfortunately (having seen this problem in action for many years) there is no one-line solution to this problem. The proper comparison will depend on your calculations, the input values, and what you are using your results for.
www.IconsReview.com <-- Huge list of stock icon collections (both free and commercial)
Very true and that's why I said, "A tactic similar to this can be used." Personally I always compare to a "tolerance" value and that works well. The big issue is - what do you use for a tolerance value ? That varies according to the circumstances as you said.
-
I may have oversimplified. The case was more like the following: double dTime = 0.; double dT = atof(<some value read in a file>); double dFinal = atof(<some value read in a file>); do{ ... dTime += dT; ... while(dTime < dFinal); A loop was missing because of the 'epsilon' induced by atof.
Where do you expect us to go when the bombs fall?
Ravi's statement still holds. Floating point addition is bad, multiplication is good. What is 20.0 + 0.000000000000000000000000000001? 20 There isn't enough mantissa to hold all the digits. Then you add in the fact that floating point is basically base 2 while our math is base 10, floating point doesn't have much hope of representing numbers exactly. That is why banks used such things as scaled integers.
Tim Smith I'm going to patent thought. I have yet to see any prior art.
-
Very true and that's why I said, "A tactic similar to this can be used." Personally I always compare to a "tolerance" value and that works well. The big issue is - what do you use for a tolerance value ? That varies according to the circumstances as you said.
Rick York wrote:
Very true and that's why I said, "A tactic similar to this can be used."
Don't take any offense - I wasn't trying to be pedantic (or bust your chops on the subject) I just wanted any newbie readers to be clear that there isn't a one-liner fix to the problem; after all this is the subtle bugs board.
Rick York wrote:
The big issue is - what do you use for a tolerance value ?
Yes! :sigh: the million dollar question...
www.IconsReview.com[^] Huge list of stock icon collections (both free and commercial)
-
Very true and that's why I said, "A tactic similar to this can be used." Personally I always compare to a "tolerance" value and that works well. The big issue is - what do you use for a tolerance value ? That varies according to the circumstances as you said.
-
Very true and that's why I said, "A tactic similar to this can be used." Personally I always compare to a "tolerance" value and that works well. The big issue is - what do you use for a tolerance value ? That varies according to the circumstances as you said.
-
Ravi's statement still holds. Floating point addition is bad, multiplication is good. What is 20.0 + 0.000000000000000000000000000001? 20 There isn't enough mantissa to hold all the digits. Then you add in the fact that floating point is basically base 2 while our math is base 10, floating point doesn't have much hope of representing numbers exactly. That is why banks used such things as scaled integers.
Tim Smith I'm going to patent thought. I have yet to see any prior art.
Tim Smith wrote:
Ravi's statement still holds. Floating point addition is bad, multiplication is good.
Mine still holds too, beware atof. I believe you could get the same result without any addition or multiplication (whose I doubt it is good). Introduction of an epsilon by atof is not indicated in the documentation[^]. Some might be fooled.
Tim Smith wrote:
scaled integers
Replacing a double by a structure of an integer and a floating point position?
Where do you expect us to go when the bombs fall?
-
I really do think the compiler should throw an error when you try to compare floating point values for equality.
cheers, Chris Maunder
CodeProject.com : C++ MVP
A warning may be sufficient, like the ';' after a 'if'. In my case, that would not have been enough. Guys who made that code didn't believe in warnings. When I reactivated the compiler option, over 1,400 warnings popped up at the first rebuild. Yeepee.
Where do you expect us to go when the bombs fall?