Author Topic: A programming challenge all up in your face.  (Read 15382 times)

TheQuirk

  • VIP
  • Member
  • ***
  • Posts: 2,154
  • Kudos: 315
Re: A programming challenge all up in your face.
« Reply #90 on: 7 October 2006, 09:39 »
I wrote a bunch of thing, but after I looked at the previous posts, it turned out that I didn't need to write them! So, useless post. Looking at code now.
« Last Edit: 7 October 2006, 09:55 by TheQuirk »

mobrien_12

  • VIP
  • Member
  • ***
  • Posts: 2,138
  • Kudos: 711
    • http://www.geocities.com/mobrien_12
Re: A programming challenge all up in your face.
« Reply #91 on: 8 October 2006, 06:59 »
Quote from: worker201
Any suggestions?


The logic seems good... the only problem seems to be that in the shuffle you somehow broke the discriminant calculations.  Actually, I broke them too when I was making the changes I posted above, and it took a while to figure it out then, so I know it's really easy to break them when shuffling ... In my case I lost the slope= line and everything went to hell :)

It's probably something really simple to fix.

I put the troubleshooting frprintf statements that I  was using earlier into this latest version and you can see the difference for the basic test case
Code: [Select]

0
0
10
10
2
5 5 1
20 20 2

Quote from: new version

terms a, b c discrim 1.000000 -0.000000 0.000000 0.000000
circle # 1 does not intersect the line
terms a, b c discrim 1.000000 -0.000000 0.000000 0.000000
circle # 2 does not intersect the line

Quote from: old version edited by mobrien

terms a, b c discrim 2.000000 -20.000000 49.000000 8.000000
terms a, b c discrim 2.000000 -80.000000 796.000000 32.000000
circle # 2 does not intersect the line
In brightest day, in darkest night, no evil shall escape my sight....

worker201

  • Global Moderator
  • Member
  • ***
  • Posts: 2,810
  • Kudos: 703
    • http://www.triple-bypass.net
Re: A programming challenge all up in your face.
« Reply #92 on: 8 October 2006, 08:00 »
I could probably fix it, by adding the contents of the function back into main.  I just figured it was stupid to write the exact same code twice.  That's what functions are for, right?  I think the program as it stands right now looks terrible, and requires too much maintenance.  All those ifs and elses, with the attendant braces and indents, are difficult to keep up with.  Then again, it would be even more of a pain in the ass to keep passing array variables back and forth through blackbox functions.  What's a boy to do?

I was reading the criticisms of C on wikipedia.  Too easy to get something wrong, and too hard to get something right.  I think that's somewhat accurate.

mobrien_12

  • VIP
  • Member
  • ***
  • Posts: 2,138
  • Kudos: 711
    • http://www.geocities.com/mobrien_12
Re: A programming challenge all up in your face.
« Reply #93 on: 8 October 2006, 10:48 »
But, as you wrote it, the function has nothing to do with the discriminant calculation.  It calculates path length.  The discriminant is used first to decide if the function should be called or not.  The discriminant calculation is what is broken.  

I'm pretty sure this is a little bug and has nothing to do with your decision to split repeated code off into a function, which I totally agree is what is the issue... nor is it particularly more difficlult in C in this case I think...even Octave is a pain in the ass when you have a hiccup.  This is just a little glitch you picked up when shuffling your code around.   :)
In brightest day, in darkest night, no evil shall escape my sight....

TheQuirk

  • VIP
  • Member
  • ***
  • Posts: 2,154
  • Kudos: 315
Re: A programming challenge all up in your face.
« Reply #94 on: 8 October 2006, 10:55 »
Suggestion: Why not make a function where you pick which variable is independent, and which is dependent? That way you could have something along the lines of the following.

Code: [Select]
if (x1 == x2) {
      happyfunction(y1, y2, x1, x1);
   }
   else {
      happyfunction(x1, x2, y1, y2);
   }

mobrien_12

  • VIP
  • Member
  • ***
  • Posts: 2,138
  • Kudos: 711
    • http://www.geocities.com/mobrien_12
Re: A programming challenge all up in your face.
« Reply #95 on: 8 October 2006, 20:51 »
Quote from: TheQuirk
Suggestion: Why not make a function where you pick which variable is independent, and which is dependent? That way you could have something along the lines of the following.

Code: [Select]
if (x1 == x2) {
      happyfunction(y1, y2, x1, x1);
   }
   else {
      happyfunction(x1, x2, y1, y2);
   }


Hmm.  That's a good idea for my variation on Worker's code, rather than alter the way the data is loaded into variables...
In brightest day, in darkest night, no evil shall escape my sight....

worker201

  • Global Moderator
  • Member
  • ***
  • Posts: 2,810
  • Kudos: 703
    • http://www.triple-bypass.net
Re: A programming challenge all up in your face.
« Reply #96 on: 9 October 2006, 01:46 »
After inserting a bazillion little printf statements at various places, I have found that my program is no longer reading the data from the file properly.  All potentially floating point values have been declared as doubles.  I suppose for test purposes, they could all be read as integers, but for functionality, I want the input file to possible contain a decimal point.

Using %f statements, like:
fscanf(fRead, "%f%f%f", &circlex, &circley, &radius);
I get:
circlex[0]=0.000000
circley[0]=-0.000000
radius[0]=nan

If I switch them to %g, I get garbage for circlex, negative garbage for circley, and nan for radius.

WTF?

This worked when they were all floats.  Does fscanf require double input to have a decimal place?  Should I read the data as type float and convert to type double afterwards?  This language is pissing me off right now.

H_TeXMeX_H

  • Member
  • **
  • Posts: 1,988
  • Kudos: 494
    • http://draconishinobi.50webs.com/
Re: A programming challenge all up in your face.
« Reply #97 on: 9 October 2006, 03:28 »
The problem with converting float to double is some loss in accuracy. If you can't get it to work with doubles then just use float, but know that your answer may be slightly innacurate (not enough to mean too much).

mobrien_12

  • VIP
  • Member
  • ***
  • Posts: 2,138
  • Kudos: 711
    • http://www.geocities.com/mobrien_12
Re: A programming challenge all up in your face.
« Reply #98 on: 10 October 2006, 02:49 »
Quote from: worker201

Using %f statements, like:
fscanf(fRead, "%f%f%f", &circlex, &circley, &radius);
I get:
circlex[0]=0.000000
circley[0]=-0.000000
radius[0]=nan



Ah..  Found it.  Double precisions have a different format code, becasue they are different kinds of variables.  I never really used doubles, mostly becasue I never cared about the tiny benefits in accuracy they bring, so I didn't know this before.  They take twice as much ram and unless you are on a 64-bit platform you take a computational power hit.

The format code is %lf instead of %f.  Interestingly enough, you apply the same "l" (that's an "l" as in "long" not the number one) modifier to integers if you use double length integers.

Try this instead:
Code: [Select]

fRead = fopen(infilename, "r");
if (fRead==NULL) {
printf("input file unavailable\n");
return 1;
}
fscanf(fRead, "%lf", &x1);
fscanf(fRead, "%lf", &y1);
fscanf(fRead, "%lf", &x2);
fscanf(fRead, "%lf", &y2);
fscanf(fRead, "%d", &numcirc);
printf("x1 %lf y1 %lf x2 %lf y2 %lf numcirc %i\n",x1,y1,x2,y2,numcirc);
if (numcirc>15) {
printf("too many circles, aborting\n");
return 1;
}
for(i=0; i fscanf(fRead, "%lf%lf%lf", &circlex[i], &circley[i], &radius[i]);
printf("circledata x %lf y %lf r %lf \n",circlex[i],circley[i],radius[i]);
}
fclose(fRead);

In brightest day, in darkest night, no evil shall escape my sight....

mobrien_12

  • VIP
  • Member
  • ***
  • Posts: 2,138
  • Kudos: 711
    • http://www.geocities.com/mobrien_12
Re: A programming challenge all up in your face.
« Reply #99 on: 10 October 2006, 03:54 »
The program still returns NAN... tracked it down to the function.  One small error.. the includes must be in front of the function too, it's not much different than writing them in separate files.

Code: [Select]



/* BEGIN THE CALCARC FUNCTION */
#include
#include

double calcarc(double update,double rad,double chord,int a)
{
  /* variable declarations */
 
  double theta;
  double rsquare;
  double arc;

  printf( "In startof calcarc, current total is %lf\n", update);
  rsquare = pow(rad, 2);
  printf( "rsquare %lf, chordsquare, %lf\n", rsquare, pow(chord,2));
  printf( "argument to acos is %lf\n", ( ( (2 * rsquare) - pow(chord, 2) ) / (2 * rsquare)  ));
  printf( "acos is %lf\n", acos( ( (2 * rsquare) - pow(chord, 2) ) / (2 * rsquare)  ));
  theta = acos( ( (2 * rsquare) - pow(chord, 2) ) / (2 * rsquare)  );
  printf( "theta %lf\n", theta);
  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;
    }
}



The problem is that acos is not defined for some reason.. it's returning NAN instead of 2pi.  I can't figure out why right now.. gotta go to bed.
In brightest day, in darkest night, no evil shall escape my sight....

worker201

  • Global Moderator
  • Member
  • ***
  • Posts: 2,810
  • Kudos: 703
    • http://www.triple-bypass.net
Re: A programming challenge all up in your face.
« Reply #100 on: 10 October 2006, 05:38 »
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

  • Global Moderator
  • Member
  • ***
  • Posts: 2,810
  • Kudos: 703
    • http://www.triple-bypass.net
Re: A programming challenge all up in your face.
« Reply #101 on: 10 October 2006, 08:06 »
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: [Select]
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);

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: [Select]
value of blah is -1.000000000000001776356839
value of theta is nan
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

  • VIP
  • Member
  • ***
  • Posts: 2,138
  • Kudos: 711
    • http://www.geocities.com/mobrien_12
Re: A programming challenge all up in your face.
« Reply #102 on: 10 October 2006, 13:54 »
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.


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: [Select]
value of blah is -1.000000000000001776356839
value of theta is nan

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.  


#$%^.  What was the explodey head thing pofnlice used???
In brightest day, in darkest night, no evil shall escape my sight....

worker201

  • Global Moderator
  • Member
  • ***
  • Posts: 2,810
  • Kudos: 703
    • http://www.triple-bypass.net
Re: A programming challenge all up in your face.
« Reply #103 on: 10 October 2006, 18:01 »
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.
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

  • VIP
  • Member
  • ***
  • Posts: 2,138
  • Kudos: 711
    • http://www.geocities.com/mobrien_12
Re: A programming challenge all up in your face.
« Reply #104 on: 11 October 2006, 23:52 »
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: [Select]

/* 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;
    }
}




Result now :)

Quote

0
0
10
10
2
5 5 1
20 20 2


Original line length = 14.142136
Final path Length= 15.283728


Actual answer is 15.28372827

Thus perfect... but should be tested with an off axis case.
In brightest day, in darkest night, no evil shall escape my sight....