11-24-2010 02:53 PM - edited 11-24-2010 02:59 PM
I'm not sure if there were past Nuggets in the CVI forum, but here is my first nugget: Dealing with Doubles
I read an interesting article today: http://www.exploringbinary.com/the-answer-is-one-unless-you-use-floating-point/
As I am mostly active in the LabVIEW Forum, I will do a cross post because I want to do a comparison between CVI and LabVIEW when dealing with doubles. I have not yet implemented the code in LabVIEW, but I do expect the same results.
In the article by Rick Regan, he explains the results that was obtained when running his function. I have duplicated is function and add my own main function below.
#include <utility.h>
#include <ansi_c.h>
#include <userint.h>
// Prototypes
double f(double a);
void main (void)
{
int i;
double result;
double myArray[21] = { 5.1, 91.3, 451.9, 7341.4, 51367.7, 897451.7,
1923556.4, 59567771.9, 176498634.7,
2399851001.7, 60098761442.7,
772555211114.1, 1209983553611.9,
59871426773404.9, 190776306245331.2,
2987154209766221.6, 19843566622234755.9,
719525522284533115.3, 8399871243556765103.9,
39847765103525225199.1, 553774558711019983333.9 };
for( i = 0; i < 21; i++)
{
result = f ( myArray[i] );
printf("f(%22.1f) \t = %18.17f \n", myArray[i], result );
}
while ( !KeyHit() )
GetKey(); // to see the io screen before the program closes
}
double f(double a)
{
double b, c;
b = 10*a - 10;
c = a - 0.1*b;
return (c);
}
As expected, I get the same output as Rick.
Rick's output:
My output (and yes, I was lazy and did not create a pretty table.. I just wanted to show a comparison of the values).
You can read the article (link provided above) for more details on the values obtained above. However, the message I am trying to convey is that you have to be careful when "dealing with doubles". Often I see code where there is an if statement that compares the value to zero.
For instance something like:
if ( double zero == 0 )
{
// then do something when true
}
and people get upset and frustrated because they do not understand why the true case never gets executed. As a matter of fact, I do recall several discussions on this topic in the LabVIEW forum. I have actually seen the discussion turn into an argument. 😄
What is important to understand is how the processor interprets double values.
I hope this information will save someone some headaches..
RayR
11-24-2010 04:08 PM
Thanks Ray for this nugget.
I had fallen across such cases in the past enough times to have learned not to perform any exact match on doble values ![]()
Now your example gives me a reason for this.
The accuracy of binary representation of doubles has been discussed several times in this forums: in addition to posts that explicitly mention IEEE754 standard I remember a few ones that also cover this subject (for example this thread and this one), but indeed having it explained in a good way is a valuable addition on this subject!
And yes: you should be awarded for posting the first nugget on the CVI board! ![]()
11-25-2010 12:50 AM
if I may join... for the very same reason I use functions such as
BOOL MathIsZero ( double a )
{
if ( fabs ( a ) < 1.0E-308 )
{
return ( TRUE );
}
else
{
return ( FALSE );
}
}
11-25-2010 07:21 AM
Absolutely, everyone can join 🙂
if ( fabs ( a ) < 1.0E-308 )
E-308??
Hummm.... what happens if fabs(a) < 1.0E-307? 😉
Once you understand the issue with doubles, the next issue is to define an acceptable range for zero.
11-25-2010 08:13 AM - edited 11-25-2010 08:19 AM
Sorry, I should not have been kidding with the range for doubles...
Here is a list of values that I use for the range that represents zero for Float, Double & Long Double
#define FLT_MIN 1.17549435e-38F
#define DBL_MIN 2.2250738585072014e-308
#define LDBL_MIN 2.2250738585072014e-308L
WHich actually brings up another subject... Maximum values when declaring doubles.
#define FLT_MAX 3.40282347e+38F
#define DBL_MAX 1.7976931348623157e+308
#define LDBL_MAX 1.7976931348623157e+308L
11-25-2010 09:12 AM
You can also use EPSILON, which is the min delta for a number in the floats or double vars.
So,
if((( x < ( 0.0 + EPSILON) && (x > (0.0 – EPSILON)))
determines if x is within the bounds of calculation of 0.
Where Epsilon is defined as:
#define FLT_EPSILON 1.19209290e-07F
#define DBL_EPSILON 2.2204460492503131e-16
#define LDBL_EPSILON 2.2204460492503131e-16L
11-25-2010 09:31 AM
Of course one can use it...
but I don't think it is a good idea...
For example, if one is calculating the second, third or forth moment of a distribution (number of measurement results ...) these numbers are small, 10-10 to 10-30..., but their roots (second third, forth) yield interesting information. Setting 10-20 equal to zero would ruin this approach...
I agree that EPSILON may be useful to check e.g. for convergence, but then I would compare the result to epsilon, not zero...
11-29-2010 12:55 PM
By the way, there's a function in the Programmer's Toolbox, FP_Compare, which does a fuzzy comparison of two doubles, based on an Epsilon that is defined in toolbox.h.
The function help has some background information on this issue (although the list of compilers looks sorrily out of date).
Luis
11-29-2010 01:55 PM
Thanks Luis,
I was not aware of thise functions. I will have to try them out.
🙂