Want to protect your cyber security and still get fast solutions? Ask a secure question today.Go Premium

x
  • Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 195
  • Last Modified:

anyone able to explain this???

i am using vc++ on win2k.

i was doing a simple loop, and found out that the code below behaves differently under release build and debug build.

it simply outputs integer i from 0 to 10 inclusive,
float f from 0 to 1 in steps of 0.1 inclusive,
float j from 0.25 to 2 in steps of 0.25 inclusive,
and double d from 0 to 1 in steps of 0.1 inclusive.

this works fine in debug build, BUT in release mode, float f only runs up to 0.9!!!

what is going on????? i attatch the exact code. i thought it may have something to do with doubles and floats, but float j works just fine in both modes.

i tried this:

#include <iostream>
using namespace std;

void main()
{

     for (int i = 0; i<=10; i++)
     {
          cout<<"i = "<<i<<endl;
     }

     for (float f = 0.0; f <=1.0; f+= 0.1)
     {
         
          cout<<"f = "<<f<<endl;
     }

     for (float j = 0.25; j <= 2.0; j+= 0.25)
     {
          cout<<"j = "<<j<<endl;
     }

     for (double d = 0.0; d < 1.0; d+= 0.1)
     {
          cout<<"d = "<<d<<endl;
     }
}
0
calum
Asked:
calum
1 Solution
 
Kent OlsenData Warehouse Architect / DBACommented:

Double WILL quit looping before d reaches 1.0.

Check your test:

for (; d < 1.0; d+= 0.1)

Kdo
0
 
calumAuthor Commented:
err, running code above DOES run to 1

and it should have been
for (double d = 0.0; d <= 1.0; d+= 0.1)
    {
         cout<<"d = "<<d<<endl;
    }
which still runs to 1.

the problem i spotted was with float f, which does NOT run to 1

i;m confused!
0
 
KocilCommented:
0
Concerto Cloud for Software Providers & ISVs

Can Concerto Cloud Services help you focus on evolving your application offerings, while delivering the best cloud experience to your customers? From DevOps to revenue models and customer support, the answer is yes!

Learn how Concerto can help you.

 
jasonclarkeCommented:
It is always dangerous to do exact comparisons against floating point values: rounding errors may mean that the value is not quite what you expect.

It is always safest to do double comparison against an acceptable range that is respects the tolerance of the value, i.e. something like:

#include <math.h>

for (float f = 0.0; (f-1.0)<1e-6; f+= 0.1)
{
    cout<<"f = "<<f<<endl;
}

0
 
calumAuthor Commented:
what i don;t understand is how the float j in the example above runs thru till the end (last number 2) but the float f only runs to 0.9. Also, i don;t get how it works under debug mode but not release mode. i;m worried about a lot of other code i;ve written, tested in debug and then relied on the answers generated by release versions.
0
 
gotenksCommented:
if you would just like a solution, i have tried various way, and finally this turn out to print the 1. but if you need explanation, sorry i don't know why either. :>

#include <iostream.h>
int main() {
   ...
   
   // declare another variable to test the condition
   float temp = 0.0;
   for ( float f = 0.0; temp <= 1.0; f += 0.1)
   {
      temp = f;
      cout<< "f = " << f <<endl;
   }
   ...
   return 0;
}

hope this help.
0
 
calumAuthor Commented:
thansk gotenks - but i;m looking for an explaination. particularly the difference in float f and float j, why one works and not the other, and why the difference between release and debug modes

calum
0
 
jasonclarkeCommented:
> but i;m looking for an explaination. particularly

As I mentioned, it is a rounding problem, i.e. in floating point aritmetic, the result of addition is only approximate.

As for the differences adding 0.25 may well be 'more stable' than adding 0.1 hence the difference.

For debug vs. release floating point arithmetic may be handled differently in release more - i.e. possibly with no checking or directly in hardware (FPU).

The point is that you should never compare floating point numbers directly for equality.  As I mentioned you should always allow some acceptable tolerance for rounding problems.
0
 
calumAuthor Commented:
that much i guessed. anyone got a definitive answer?

0
 
jasonclarkeCommented:
> anyone got a definitive answer?

what more do you want?  There is no more that I can think of - the problem is that floating point arithmetic is not exact.  What else is there to know?
0
 
calumAuthor Commented:
i;m concerned about the differencing between the debug and release builds handling the floats differently
0
 
jasonclarkeCommented:
> i;m concerned about the differencing between the debug > and release builds handling the floats differently

As I said any number of factors can make a difference between debug and release modes, for example:

- hardware vs. software arithmetic
- different precision used 'under the covers' in calculations
- different checking - debug arithmetic is usually checked
- compiler code optimisations

but really it is irrelevant.  The fact is that any number of factors could change the result of a floating point calculation and so checking the result of a floating point calculation using a direct equality check is *always* a bad idea - the difference is more than just between debug and release modes - just moving the same program (i.e. the same binary) to different hardware could cause the result to change.

If this kind of thing is at all important to you then these checks should be done against some sort of acceptable tolerance value.
0
 
calumAuthor Commented:
fair enough. it is quite important as i;m doing some maths stuff. maybe i;ll just use doubles ... i don;t want to have some tolerance check on every comparison i do - i do loads of them.

you get the points, thanks for your help
0
 
jasonclarkeCommented:
> maybe i;ll just use doubles

even this is not entirely safe.  If it is important then you really should use a tolerance value.  You can wrap it up in a function if you like:

const float tolerance = 1e-6;

inline bool floatEquals(float f1, float f2)
{
    return fabs(f1-f2) < tolerance;
}

inline bool floatLTE(float f1, float f2)
{
    return f1-f2 < tolerance;
}

then

for (float f = 0.0; floatLTE(f,1.0); f+= 0.1)
{        
   cout<<"f = "<<f<<endl;
}

0

Featured Post

[Webinar On Demand] Database Backup and Recovery

Does your company store data on premises, off site, in the cloud, or a combination of these? If you answered “yes”, you need a data backup recovery plan that fits each and every platform. Watch now as as Percona teaches us how to build agile data backup recovery plan.

Tackle projects and never again get stuck behind a technical roadblock.
Join Now