-
Debug works, Release doesn't?
I came across this in my MFC app and simplified the code into this console app for this example. When I compile and run the following code in Debug mode, it gives the correct answer for i, (10). When I compile and run it in Release mode, it gives the wrong answer for i, (11). Anyone know why?
Code:
#include <iostream>
using namespace std;
void main(){
int i;
double yTest;
i=0;
yTest = 100000000.;
while (yTest-.01 > 0.){
yTest /= 10.;
i++;
}
cout<<i<<endl;
}
VS 2003 .Net Version 7.1.3088
-
Re: Debug works, Release doesn't?
Release mode frequently uses "fast math" computations which are faster but slightly less accurate. Of course, expecting something like this to be completely accurate seems rather dubious anyway.....floats dinnae work like that.
Any math that can be "broken" by a change in compile settings does not exhibit numerical stability, which is a highly desirable property for computer programs.
-
Re: Debug works, Release doesn't?
I've just tested this code in VS2008 and result is the same for both Release and Debug: it is 10
-
Re: Debug works, Release doesn't?
So where is the instability in my code? I totally expected this to work no matter how it was compiled? How should it be written? :confused:
-
Re: Debug works, Release doesn't?
Thanks, Victor. I was afraid of that. Guess I'll have to write some hack code to deal with it until I can upgrade.
-
Re: Debug works, Release doesn't?
Interesting! VC++6.0 gave me the same results as your VS 2003:
10 - for Debug
11 - for Release
:confused: :rolleyes:
-
Re: Debug works, Release doesn't?
Quote:
Originally Posted by
lspecht
So where is the instability in my code?
0.1 is not an exact binary floating point number. Therefore your loop is ill-formed, as there is no guarantee how many times it will execute.
The bottom line is that loop counters should be done in integer, not floating point. If you know you must loop 10,000 times, then specifiy that explicitly using integer.
Regards,
Paul McKenzie
-
Re: Debug works, Release doesn't?
Read the message here, and go to the link concerning using floating point math as loop controllers.
http://www.codeguru.com/forum/showpo...52&postcount=3
Regards,
Paul McKenzie
-
Re: Debug works, Release doesn't?
The problem is I don't know how many times the loop needs to run. It will likely be different every time. Your point should be taken care of by the fact that I'm using > and not an exact equality to exit the loop.
-
Re: Debug works, Release doesn't?
Paul,
I have a better understanding now that I read the post you referenced. Thanks for the information. I'll have to think of a solution that will work no matter which compiler option I use.
-
Re: Debug works, Release doesn't?
OK, let's simplify this test:
Code:
#include <iostream>
#include "tchar.h"
using namespace std;
int _tmain(int argc, TCHAR* argv[])
{
double yTest;
yTest = 0.1;
yTest /= 10.;
if(yTest > .01)
printf("yTest > .01\n");
else
printf("yTest <= .01\n");
return 0;
}
The results:
VC++6.0, Debug:VC++6.0, Release:VS2008, Debug:VS2008, Release::confused: :confused:
-
Re: Debug works, Release doesn't?
Quote:
Originally Posted by
lspecht
Paul,
I have a better understanding now that I read the post you referenced. Thanks for the information. I'll have to think of a solution that will work no matter which compiler option I use.
Unless I'm totally off, you can try the following as a hint:
The number of times you loop will be based on the log10 of yTest.
Regards,
Paul McKenzie
-
Re: Debug works, Release doesn't?
Quote:
Originally Posted by
VictorN
OK, let's simplify this test:
Code:
#include <iostream>
#include "tchar.h"
using namespace std;
int _tmain(int argc, TCHAR* argv[])
{
double yTest;
yTest = 0.1;
yTest /= 10.;
if(yTest > .01)
printf("yTest > .01\n");
else
printf("yTest <= .01\n");
return 0;
}
The results:
VC++6.0, Debug:
VC++6.0, Release:
VS2008, Debug:
VS2008, Release:
:confused: :confused:
The problem is that 0.1 has no exact binary representation, and dividing that number by 10 incurs more round-off error. How much round-off error depends on compiler, compiler options, etc.
If you started yTest at 0.5 and then divided by 2, you should see that the results are the same, regardless of compiler, compiler options, etc.
Regards,
Paul McKenzie
-
Re: Debug works, Release doesn't?
Quote:
Originally Posted by
Paul McKenzie
The problem is that 0.1 has no exact binary representation, and dividing that number by 10 incurs more round-off error.
I agree!
What I couldn't understand is why:
either binary representation of 0.1 differs for Debug and Release
or FP-divide operation is performed differently for Debug and Release.
-
Re: Debug works, Release doesn't?
Quote:
Originally Posted by
VictorN
I agree!
What I couldn't understand is why:
either binary representation of 0.1 differs for Debug and Release
or FP-divide operation is performed differently for Debug and Release.
Probably the latter. I remember that different compilers do different things with the floating point unit, even things that seem as simple as a division.
A look at the assembly code would answer the question of what really happens during the division.
Regards,
Paul McKenzie
-
Re: Debug works, Release doesn't?
Paul,
The log10(yTest) is 8 so that won't work. I tried the following and it too fails for the Release mode which i=30 instead of 10. Debug i=10. I suspect this is the same problem. Exact equality won't work in this case either.
Code:
#include <iostream>
using namespace std;
void main(){
int i;
double yTest;
yTest = 100000000.;
for(i=0;i<30;i++){
if(yTest-.01 == 0.) break;
yTest /= 10.;
}
cout<<i<<endl;
}
-
Re: Debug works, Release doesn't?
Quote:
Originally Posted by
lspecht
Paul,
The log10(yTest) is 8 so that won't work.
Add 2 to that, since you are dividing by 10^(-2). I stated that log10 is a hint, not the exact answer. The number of times you loop in the first example is related to the number of digits in the number.
Regards,
Paul McKenzie
-
Re: Debug works, Release doesn't?
That would work for this example, however, I oversimplified my example. In my app, yTest can be any power of 10 and the .01 can be any power of 10 less than yTest. For the next case it could be yTest = 1000. and .000001. The problem is to determine the number of powers of 10 in the spread.
-
Re: Debug works, Release doesn't?
Sorry. I didn't read all of your last post. I need to think about it some more.
-
Re: Debug works, Release doesn't?
When using logs to determine number of digits, you have to be careful about boundary cases. I don't recall the exact rule offhand, though.
-
Re: Debug works, Release doesn't?
Quote:
Originally Posted by
lspecht
That would work for this example, however, I oversimplified my example. In my app, yTest can be any power of 10 and the .01 can be any power of 10 less than yTest. For the next case it could be yTest = 1000. and .000001. The problem is to determine the number of powers of 10 in the spread.
Another possible solution is to normalize yTest as an integer (multiply it by 100, 1000, whatever). Then use that to figure out
1) How many times to loop.
2) The formula you use within the loop.
If you have 64-bit ints (you should), then maybe this is another approach you can take. Make yTest a 64-bit int, and see how that shakes out.
Regards,
Paul McKenzie
-
Re: Debug works, Release doesn't?
After thinking about your suggestion, Paul, :o I came up with this solution that should work. I'll have to add code to test for when y2Test is 1 or greater then subtract instead of add but that is straightforward. Note, I replaced the .01 with y2Test which I should have done in my original example since it is variable.
Thanks for all the help, everyone.
Code:
#include <iostream>
#include <math.h>
using namespace std;
void main(){
double i;
double yTest;
double y2Test;
yTest = 100000000.;
y2Test = .01;
i = abs(log10(yTest)) + abs(log10(y2Test));
cout<<i<<endl;
}
-
Re: Debug works, Release doesn't?
Quote:
Originally Posted by
lspecht
After thinking about your suggestion, Paul, :o I came up with this solution that should work. I'll have to add code to test for when y2Test is 1 or greater then subtract instead of add but that is straightforward. Note, I replaced the .01 with y2Test which I should have done in my original example since it is variable.
OK. But make sure you test on the different compilers. It still uses some floating point, but as long as "i" is the same then you should be OK.
I still think that normalizing everything to int, and doing the floating point calculations inside the loop is the way to go though.
Also, one more thing -- main() returns int, not void.
Regards,
Paul McKenzie