?
Solved

anyone able to explain this???

Posted on 2003-03-13
14
Medium Priority
?
193 Views
Last Modified: 2010-04-01
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
Comment
Question by:calum
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
14 Comments
 
LVL 46

Expert Comment

by:Kent Olsen
ID: 8129166

Double WILL quit looping before d reaches 1.0.

Check your test:

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

Kdo
0
 

Author Comment

by:calum
ID: 8129249
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
 
LVL 5

Expert Comment

by:Kocil
ID: 8129260
0
What does it mean to be "Always On"?

Is your cloud always on? With an Always On cloud you won't have to worry about downtime for maintenance or software application code updates, ensuring that your bottom line isn't affected.

 
LVL 9

Expert Comment

by:jasonclarke
ID: 8129523
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
 

Author Comment

by:calum
ID: 8129606
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
 

Expert Comment

by:gotenks
ID: 8134238
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
 

Author Comment

by:calum
ID: 8134524
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
 
LVL 9

Expert Comment

by:jasonclarke
ID: 8134966
> 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
 

Author Comment

by:calum
ID: 8136333
that much i guessed. anyone got a definitive answer?

0
 
LVL 9

Expert Comment

by:jasonclarke
ID: 8136353
> 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
 

Author Comment

by:calum
ID: 8136375
i;m concerned about the differencing between the debug and release builds handling the floats differently
0
 
LVL 9

Accepted Solution

by:
jasonclarke earned 200 total points
ID: 8136437
> 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
 

Author Comment

by:calum
ID: 8136522
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
 
LVL 9

Expert Comment

by:jasonclarke
ID: 8136633
> 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

VIDEO: THE CONCERTO CLOUD FOR HEALTHCARE

Modern healthcare requires a modern cloud. View this brief video to understand how the Concerto Cloud for Healthcare can help your organization.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Article by: SunnyDark
This article's goal is to present you with an easy to use XML wrapper for C++ and also present some interesting techniques that you might use with MS C++. The reason I built this class is to ease the pain of using XML files with C++, since there is…
Written by John Humphreys C++ Threading and the POSIX Library This article will cover the basic information that you need to know in order to make use of the POSIX threading library available for C and C++ on UNIX and most Linux systems.   [s…
The goal of the video will be to teach the user the concept of local variables and scope. An example of a locally defined variable will be given as well as an explanation of what scope is in C++. The local variable and concept of scope will be relat…
The viewer will learn how to pass data into a function in C++. This is one step further in using functions. Instead of only printing text onto the console, the function will be able to perform calculations with argumentents given by the user.
Suggested Courses

765 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question