Miscellaneous > Programming & Networking
A programming challenge all up in your face.
worker201:
Out of 3 C books, including K&R, the %lf was mentioned only once. All other data pointed to %f or %e or %g being just fine for both floats and doubles.
Declaring the includes before the functions makes no sense whatsoever. I'm going to have to look that up. Especially since I have plans to make the distance calculations into functions.
worker201:
Well, adding includes to the functions did nothing, as I sort of expected - that would not have made any sense, and there is no precedent for it anywhere on the net I could find.
However, after some serious searching, I did figure out why acos is returning nan. Consider the following bit of my calcarc function:
--- Code: ---blah = (2 * rsquare - pow(chord, 2)) / (2 * rsquare);
printf("value of blah is %.25g\n", blah);
theta = acos(blah);
printf("value of theta is %g\n", theta);
--- End code ---
This is the computation for the law of cosines, done in 2 steps to monitor what is being sent to acos. We all know (at least those of us who have read hundreds of web pages about math.h) that the acos function only accepts values -1 < x < 1. If you calculate it out by hand, you will find that the test data yields a value for blah of -1, totally legal. But then notice the output, and especially notice the 25 decimal places of precision:
--- Code: ---value of blah is -1.000000000000001776356839
value of theta is nan
--- End code ---
Bastard! Yes, ladies and gentlemen, we have a floating point math error! This value, which is so close to -1 it's not even funny, will cause acos to return nan. Read all about floating point math, and why it occasionally introduces such inaccuracies here:
http://en.wikipedia.org/wiki/Floating-point_number
This type of error is also one of the reasons why my test for tangency might not work - you would have to get an extremely accurate return from acos to pass the test for x == 0.
Well, the most obvious solution is to switch the whole damn thing back to floats. The result of the above would probably be -1.000000, with the insignificant bytes at the end rounded off. Since acos accepts and returns a double, the acceptable float would be transformed into an acceptable double before running the function, and then the output would be transformed back into an acceptable float afterwards.
The lesson: increasing your accuracy can come back to bite you in the ass. I'm sticking with floats, unless someone asks me to do otherwise.
mobrien_12:
The %lf fixed the input problems for you too, right? I'm wondering if gcc went more strict on the formatting conventions in later versions.... maybe if we had used full warnings we would have caught it earlier.
I did notice that %f worked fine for the format strings for doubles in printf statements... output not input.
--- Quote from: worker201 ---Well, adding includes to the functions did nothing, as I sort of expected - that would not have made any sense, and there is no precedent for it anywhere on the net I could find.
--- End quote ---
My C books had it, and the printf statements in the functions didn't work on my comp at all w/o them declared a second time. Dunno.
--- Quote ---
However, after some serious searching, I did figure out why acos is returning nan.
--- Code: ---value of blah is -1.000000000000001776356839
value of theta is nan
--- End code ---
Bastard! Yes, ladies and gentlemen, we have a floating point math error! This value, which is so close to -1 it's not even funny, will cause acos to return nan.
--- End quote ---
#$%^. What was the explodey head thing pofnlice used???
worker201:
--- Quote from: mobrien_12 ---My C books had it, and the printf statements in the functions didn't work on my comp at all w/o them declared a second time. Dunno.
--- End quote ---
I think maybe you have linker problems. I'd test it on a Linux machine if I had access to one. I have been writing, compiling, and running this program on a Mac, using vi and gcc, and things work fine. Of my 3 C books, none of them mentioned multiple #includes for one file...
FYI, the %lf thing did work, thanks for that.
mobrien_12:
OK, no need to go back to single precision... was thinking about this... if we know that a floating point error can exist, we just have to sanity check the range and make sure that the acos won't mess up. Nothing wrong with sanity checks if you have a good physical reason to do them, and we do (there is no way a chord can be more than twice as long as two radii).
--- Code: ---
/* BEGIN THE CALCARC FUNCTION */
#include
#include
double calcarc(double update,double rad,double chord,int a)
{
/* variable declarations */
double theta;
double rsquare;
double arc;
double argument;
printf( "In startof calcarc, current total is %lf\n", update);
rsquare = pow(rad, 2);
printf( "rsquare %lf, chordsquare, %lf\n", rsquare, pow(chord,2));
argument=( ( (2 * rsquare) - pow(chord, 2) ) / (2 * rsquare) );
/* we know some floating point error can creep in and cause the range of the argument
to creep slightly above 1 when using double precision, thus we must sanity check
argument and make sure this doesn't happen or the trig functions choke */
if ( ( (fabs(argument)) > (1.0) ) && ( (floor(fabs(argument))) == (1) ) )
{
/* the next line will turn argument into +1 or -1, if appropriate. */
argument=argument/fabs(argument);
}
printf( "argument to acos is %lf\n", argument );
printf( "acos is %lf\n", acos(argument) );
theta = acos( argument );
if (theta == 0)
{
printf("In calcarc, circle # %d does not intersect the line (tangent)\n", a+1);
return update;
}
else
{
printf("In calcarc, circle # %d intersects the line, calculating arc distance\n", a+1);
arc = theta * rad;
update = update - chord + arc;
printf( "In endof calcarc, current total is %lf\n", update);
return update;
}
}
--- End code ---
Result now :)
--- Quote ---
0
0
10
10
2
5 5 1
20 20 2
Original line length = 14.142136
Final path Length= 15.283728
--- End quote ---
Actual answer is 15.28372827
Thus perfect... but should be tested with an off axis case.
Navigation
[0] Message Index
[#] Next page
[*] Previous page
Go to full version