?
Solved

What effect does including float.h have?

Posted on 2006-05-29
17
Medium Priority
?
795 Views
Last Modified: 2013-11-18
I had a situation where the result of an acos() was NAN.  The argument seemed to be 1.00000 but it did not compare to (== 1.0) so it must have been off by a bit and was causing acos to return and NAN result.  So, to check for this I was going to use _isnan(), so I included float.h in my file.  All of a sudden, acos no longer returns NAN with the same argument.  It now returns zero like it should with an argument of 1.000000000.  How did just including float.h cause this to correct itself?
0
Comment
Question by:jeffs1
  • 6
  • 5
  • 2
  • +2
17 Comments
 
LVL 86

Expert Comment

by:jkr
ID: 16785236
'float.h' usually only declares the limits on the values of floating-point constants. In fact, there is no difference including it or not:

#include <stdio.h>
#include <math.h>

#include <float.h> // comment that our

int main () {

float f = 1.0;

printf("'acos(%f)' is %f\n",f,acos(f));

return 0;
}

I assume that the problem lies elsewhere...
0
 

Author Comment

by:jeffs1
ID: 16785304
I stand corrected.  It is not the inclusion of float.h that fixes the problem.  It is the call to _isnan().  Just placing this call anywhee in my code "_isnan(1.0);" keeps the return value of acos elsewhere in the code from being NAN.  So, my revised question is, what is _isnan() pulling in that is causing the return value of acos() to be correct, and what is left out that is causing the return value to be NAN when I do NOT call _isnan() in my source?
0
 
LVL 86

Expert Comment

by:jkr
ID: 16785337
I strongly doubt that this is the reason either. '_isnan()' usually just checks the integrity of the mantissa and exponent values of the parameter passed in. Yet, without the actual code, it's hard to tell. Any conditional execution paths with '_isnan()' involved?
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.

 

Author Comment

by:jeffs1
ID: 16785372
ONly difference in code is allowing or commenting the single line:

_isnan(1.0);

And I consistently cause (without it) or fix (with it) the problem.  Completely reproducable.
0
 
LVL 86

Expert Comment

by:jkr
ID: 16785377
What exactly is the float value that causes the failure?
0
 

Author Comment

by:jeffs1
ID: 16785406
It printf's as 1.000000000. But the test (var == 1.0) returns false... so I assume that it is some value greater than zero and that is causing acos to return NAN.
0
 
LVL 86

Expert Comment

by:jkr
ID: 16785418
>>But the test (var == 1.0) returns false

You should not test floating point values for accuracy like that - they'll never match. Better use

#include <limits>

bool is_equal(double d1, double d2) {

    return fabs(d1 - d2) < std::numeric_limits<double>::epsilon();
}
0
 
LVL 4

Expert Comment

by:e_tadeu
ID: 16785552
When you call _isnan, the compiler must be linking with a math library, and the initialization of this library must be changing some FPU flags (like rounding mode or error mode).

Could specify what compiler you are using and the code that is leading to this?
0
 
LVL 86

Expert Comment

by:jkr
ID: 16785663
>>When you call _isnan, the compiler must be linking with a math library

That's already the prerequisite for 'acos()' also...
0
 

Author Comment

by:jeffs1
ID: 16785704
Sorry... I should have listed that in the first post.  Visual C++ 8.0 (Visual Studio 2005).

The function simply computes the great circle distance between two lat/lon points in miles.  If I comment out the lines that test for _isnan() the acos() function returns NAN when the input lat/lon points are the same (i.e. dist should be zero)... with the line uncommented, the acos() function returns zero as it should.

int MilesBetween( double dALat, double dALon, double dBLat, double dBLon )
{
   double dCentAng;
   double dFactor = M_PI / 180.0;

   // Degrees to radians
   dALat *= dFactor;
   dALon *= dFactor;
   dBLat *= dFactor;
   dBLon *= dFactor;

   // Find GC distance
   dCentAng = acos((sin(dALat) * sin(dBLat)) + (cos(dALat) * cos(dBLat) * cos(fabs(dALon - dBLon))));
   if( _isnan(dCentAng) )
     return -1;
 
   // Radians to degrees
   dCentAng = (dCentAng * 180.0) / M_PI;

   return (int) ((dCentAng * 60.0) + 0.5);
}
0
 
LVL 86

Expert Comment

by:jkr
ID: 16785727
Hm, from a mathematical point of view, 'acos()' should never return NaN anyway. Cosine is a periodical function.
0
 
LVL 39

Expert Comment

by:itsmeandnobodyelse
ID: 16787786
acos is only defined for values between -1 and 1. If you pass a value greater than 1 acos returns NAN. See http://mathworld.wolfram.com/InverseCosine.html for more details.

Regards, Alex
0
 
LVL 85

Accepted Solution

by:
ozo earned 500 total points
ID: 16787958
Another way to find great circle distances that does not have problems with numbers very close to 1 is
cA=cos(dAlat);
cB=cos(dBlat);
sA=sin(dAlat);
sB=sin(dBlat);
cD=cB*cos(dAlon-dBlon);
c2=cB*sin(dAlon-dBlon);
c1=cA*sB-sA*cD;
dCentAng = atan2(sqrt(c2*c2+c1*c1),sA*sB+cA*CD);
0
 
LVL 85

Expert Comment

by:ozo
ID: 16787996
0
 
LVL 4

Expert Comment

by:e_tadeu
ID: 16789081
Maybe it is affecting the optimization. VC8 optimization is known to modify floating point results.
Try to compile with different /fp: flags. See:

http://msdn2.microsoft.com/en-us/library/e7s85ffb.aspx
http://msdn2.microsoft.com/en-US/library/ms235601.aspx
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dv_vstechart/html/floapoint.asp


0
 
LVL 39

Expert Comment

by:itsmeandnobodyelse
ID: 16789297
>>>> Maybe it is affecting the optimization

As explained above acos is *not defined* for arguments < -1 and > +1.

If your calculations are valid but could give results that were very near to 1 or -1, you need to make sure that the absolute value of the argument never exceeds 1. You might use a rounding function like that:

double roundCos(double d)
{
      return (d < -1.)? -1 :  (d > 1.) ? 1 : d;
}

However, first you should check whether acos(-1.) and acos(1.) return valid results.

Regards, Alex
0
 

Author Comment

by:jeffs1
ID: 16791500
Thanks to everyone for all of their help.  I am going to use the suggested GC Dist algorithm to eliminate the problem near 1...  but I will also do some more investigating out of curiosity, to find out why including/excluding the function isnan affects things... I will play with optimizations also... and look at the full floating point 4-byte value to see what is really different in both situations.
0

Featured Post

How to Use the Help Bell

Need to boost the visibility of your question for solutions? Use the Experts Exchange Help Bell to confirm priority levels and contact subject-matter experts for question attention.  Check out this how-to article for more information.

Question has a verified solution.

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

Preface This is the third article about the EE Collaborative Login Project. A Better Website Login System (http://www.experts-exchange.com/A_2902.html) introduces the Login System and shows how to implement a login page. The EE Collaborative Logi…
Basic understanding on "OO- Object Orientation" is needed for designing a logical solution to solve a problem. Basic OOAD is a prerequisite for a coder to ensure that they follow the basic design of OO. This would help developers to understand the b…
The viewer will be introduced to the technique of using vectors in C++. The video will cover how to define a vector, store values in the vector and retrieve data from the values stored in the vector.
The viewer will the learn the benefit of plain text editors and code an HTML5 based template for use in further tutorials.
Suggested Courses

862 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