Stop Microsoft

Miscellaneous => Programming & Networking => Topic started by: TheQuirk on 29 January 2006, 21:08

Title: A programming challenge all up in your face.
Post by: TheQuirk on 29 January 2006, 21:08
Ladies and gentlemen, it's time for another programming challenge. This one deals with circles and lines, so some math will be required.

A picture is worth a thousand words, so I'll start with an illustration I drew.

(http://img368.imageshack.us/img368/126/line2gu.jpg)

Your mission: Find the length of the bold curve.

Input: Your program should read a file called "INPUT," which is in the following format:

x_i
y_i
x_f
y_f
n
x_1 y_1 r_1
x_2 y_2 r_2
...
x_n y_n r_n

Example:
1
10
10
1
1
5 5 4

(x_i denotes the x-coordinate of the BEGINNING of the curve; y_i denotes of y-coordinate of the BEGINNING of the curve; x_f denotes the x-coordinate of the END of the curve; y_f denotes the y-coordinate of the END of the curve; n denotes the number of circles there are; x_j denotes the x-coordinate of the center of circle j; y_j denotes the y-coordinate of the center of circle j; r_j denotes the radius of circle j.)

None of the circles touch or intersect, and all the figures belong to the first quadrant/the two axes.

Output: your program should output the length of the curve to a file called "OUTPUT."

The following math things may prove useful.

The equation of a line with slope a and y-intercept b is y = ax + b.

The slope can be found by taking two points which belong to the line, (x_1, y_1) and (x_2, y_2), and performing the following operation:
Code: [Select]

    y_2 - y_1
a = ---------
    x_2 - x_1

The distance between two points with coordiantes (x_1, y_1) and (x_2, y_2) equals sqrt((x_2 - x_1)^2 + (y_2 - y_1)^2)

The standard equation of a circle of radius r with center at (x_0, y_o) is::
Code: [Select]

(x - x_0)^2 + (y - y_0)^2 = r^2

Note that any positive number has TWO square roots. E.g. sqrt(4) = {-2, 2}, not just 2.

A quadratic equation is an equation in the form ax^2 + bx + c = 0. The solution is this:
Code: [Select]

       -b - sqrt(b^2 - 4ac)
x_1 =  --------------------
                 2a

       -b + sqrt(b^2 - 4ac)
x_2 =  --------------------
                 2a

Note that if b^2 - 4ac > 0, then there are two solutions; if b^2 - 4ac = 0, there is one solution; if b^2 - 4ac < 0, then there are no real solutions. (The expression b^2 - 4ac is called the discriminate, and is usually represented by the capital letter D.)

When making algebraic manipulations, don't forget about the domain! For example, suppose you have to solve the following equation:
Code: [Select]

(sqrt(x))^2 = -15

The answer is "no solution"--NOT -15. The square root function has the domain [0, +inf)!

The formula for the length of an arc is:
Code: [Select]

s = Ar

Where A is the measure of the angle in radians, and r is the radius of the circle.

In addition, I suggest looking up the Law of Cosines (or, alternatively, Pythagorean
Title: Re: A programming challenge all up in your face.
Post by: Orethrius on 30 January 2006, 00:19
[offtopic]
Quote from: TheQuirk
Code: [Select]
(sqrt(x))^2 = -15
The answer is "no solution"--NOT -15. The square root function has the domain (0, +inf)!

Not intending to be a nit or anything, but isn't (√x)^2 == x, where x ≥ 0?  Sorry for the tangent, I'm just trying to see if I correctly remember my Calculus classes.

[/offtopic]
Title: Re: A programming challenge all up in your face.
Post by: H_TeXMeX_H on 30 January 2006, 01:17
[OFFTOPIC]The square root of anything squared is the absolute value of that something ... meaning a positive number[/OFFTOPIC]
Title: Re: A programming challenge all up in your face.
Post by: Pathos on 30 January 2006, 09:52
Quote from: Orethrius
[offtopic]


Not intending to be a nit or anything, but isn't (√x)^2 == x, where x ≥ 0?  Sorry for the tangent, I'm just trying to see if I correctly remember my Calculus classes.

[/offtopic]

If you use complex numbers it works, if you algebraically cancel the two operations out it works. If you attempt the find the Real root your screwed.
Title: Re: A programming challenge all up in your face.
Post by: Pathos on 30 January 2006, 09:57
Will the circles ever overlap the end points of the line?
Title: Re: A programming challenge all up in your face.
Post by: Orethrius on 30 January 2006, 18:47
Quote from: Pathos
If you use complex numbers it works, if you algebraically cancel the two operations out it works. If you attempt the find the Real root your screwed.
You have already lost.
The correct answer is always "42."

Having said that, 42.   QED. :D
Title: Re: A programming challenge all up in your face.
Post by: piratePenguin on 31 January 2006, 02:25
http://illhostit.com/files/3913162470455711/curve_q.png
Whenever the curve is going around a circle it can go around it clockwise or anti-clockwise, does it always go clockwise or should it go for the shortest route?
Title: Re: A programming challenge all up in your face.
Post by: TheQuirk on 31 January 2006, 16:32
Shortest route, and no, the circles don't overlap.

About the (sqrt(x))^2 = x thing: for x >= 0, yes, (sqrt(x))^2 = x is correct. What a lot of people do, though, is forget that the square root function has a domain of [0; inf) and solve things like (sqrt(x))^2 = -1 in the real number system.
Title: Re: A programming challenge all up in your face.
Post by: TheQuirk on 20 September 2006, 08:09
Let's take this thing apart piece  piece!

Before we write any code, we have to answer a few questions:

a) How do we represent the line mathematically?
b) How do we represent the circles mathematically?
c) How do we check whether the line touches/intersects a given circle?
d) If the line intersects a given circle, what is the arc length which is "created"?
Title: Re: A programming challenge all up in your face.
Post by: worker201 on 20 September 2006, 08:49
a)
slope = (y2-y1)/(x2-x1);
b = y1 - (slope * x1);

the line's equation is then:
y = b + (slope * x);
or maybe:
y = y1-m(x+x1);
or if you prefer:
y = y1 - (((y2-y1)/(x2-x1)) * (x+x1));

Even though the order of operations covers most of the math, I still use parentheses, for clarity.

So is that enough?  Or do we need to build some kind of array of points that satisfy the equation?
Title: Re: A programming challenge all up in your face.
Post by: TheQuirk on 20 September 2006, 08:52
Should be enough.
Title: Re: A programming challenge all up in your face.
Post by: worker201 on 20 September 2006, 10:23
Quote from: TheQuirk
Should be enough.
You're sooooooo helpful.

Okay,
(b)

how about:
y = q + sqrt(r^2 - (x-p)^2);

where p,q is the center, and r is the radius
Title: Re: A programming challenge all up in your face.
Post by: TheQuirk on 20 September 2006, 11:40
Well, what else was I supposed to say? You don't need an array because there are infinitely many possibilities of locations and radii of circles, so you can't just have an array with all the, say, points with integer coordinates and check whether they belong to the circles or not.

Anyway!

Quote
y = q + sqrt(r^2 - (x-p)^2);

Almost. That only gives you half a circle. This is what it should be:
Quote
y = q +- sqrt(r^2 - (x-p)^2);
Title: Re: A programming challenge all up in your face.
Post by: worker201 on 21 September 2006, 00:53
c) set the two y= equations above equal and solve?  But what variable do we solve for?  There are 7 unknowns, and that's for only one circle.
Title: Re: A programming challenge all up in your face.
Post by: TheQuirk on 21 September 2006, 00:57
What are the other six unknowns?
Title: Re: A programming challenge all up in your face.
Post by: H_TeXMeX_H on 21 September 2006, 02:54
<-- Wonders what possible use / real world application this rather complicated programming challange has ... I dunno, maybe it doesn't have a purpose other than to be challanging. Hmmm ... maybe I can come up with one that is a little more appilcable.
Title: Re: A programming challenge all up in your face.
Post by: Orethrius on 21 September 2006, 03:09
Aside from the arc-length bit, it seems to be a rather straightforward CAD application of some sort.
Title: Re: A programming challenge all up in your face.
Post by: worker201 on 21 September 2006, 04:56
Quote from: TheQuirk
What are the other six unknowns?
whoa, step back a second.  I guess the only thing to solve for is x.  x in terms of 7 variables.  Probably need to solve it twice, to account for the +/- thing.

My shitty math skills produced:
x = (b + p - q -r)/(1-m);
and
x = (-b -p + q + r)/(1-m);
but that probably isn't right
I suppose that if this equation has a rational answer, then the line does in fact intersect the circle, isn't that what we're getting at here?


As far as the point, one possible use for something like this is as a control mechanism for vector graphics.  You might have a matrix that defines a line and a matrix that defines a circle, and want to know where, if at all, they intersect.
Title: Re: A programming challenge all up in your face.
Post by: pofnlice on 21 September 2006, 09:13
uh oh...2 matrices?
Title: Re: A programming challenge all up in your face.
Post by: piratePenguin on 21 September 2006, 17:54
Quote from: Orethrius
Aside from the arc-length bit, it seems to be a rather straightforward CAD application of some sort.
CAD programs can/should be able to tell you the length of arcs, lines etc.

So you could modify/build a simple CAD program to do this. I was thinking of doing it with SVG and Javascript, but, nah..
Title: Re: A programming challenge all up in your face.
Post by: TheQuirk on 21 September 2006, 21:07
Quote from: H_TeXMeX_H
<-- Wonders what possible use / real world application this rather complicated programming challange has ... I dunno, maybe it doesn't have a purpose other than to be challanging. Hmmm ... maybe I can come up with one that is a little more appilcable.

The point of computer science isn't writing applicable programs. If you open a CS book, you'll find that a lot of what's discussed has very little, if any, application to the real world.

http://en.wikipedia.org/wiki/Complexity_classes_P_and_NP

A lot of math has no application. Should we stop studying math?

Something I should mention: Before we solve the general question, which has n circles, let's solve a specific case, in which the line intersects one circle, and doesn't intersect a second circle.

Anyway, that solution for x doesn't seem right. I haven't looked at what all the variables mean, but generally, if you're solving a quadratic, you should be using the quadratic formula (which involes a square and a square root). I wrote down part of the solution on a sheet of paper, but as it turns out, the scanner I was going to use isn't working, so I'll have to scan it some time later today (or type it all up in LaTeX).
Title: Re: A programming challenge all up in your face.
Post by: worker201 on 21 September 2006, 23:17
Quote from: TheQuirk
The point of computer science isn't writing applicable programs. If you open a CS book, you'll find that a lot of what's discussed has very little, if any, application to the real world.

Programming books, however, are all about the applications.  And those are far more common than CS books.  In fact, I don't think the local Barnes&Noble actually has any true CS books.
Title: Re: A programming challenge all up in your face.
Post by: H_TeXMeX_H on 22 September 2006, 00:12
Well, I agree with all that. Except math does have a lot of applications, and the parts that are not applicable are probably incorrect. As for this particular challange, I brought up this issue because I found it to be way too specific (any other arrangement of the objects in the figure would result in a useless program) and I mean I just think that it's just too damn challanging and too little motivation :(
Title: Re: A programming challenge all up in your face.
Post by: worker201 on 22 September 2006, 02:27
But, if Quirk and I manage to get through it, we'll be better programmers.
(actually, he has probably already written it, so it's just me getting better)
Title: Re: A programming challenge all up in your face.
Post by: TheQuirk on 22 September 2006, 09:35
Quote from: H_TeXMeX_H
Well, I agree with all that. Except math does have a lot of applications, and the parts that are not applicable are probably incorrect. As for this particular challange, I brought up this issue because I found it to be way too specific (any other arrangement of the objects in the figure would result in a useless program) and I mean I just think that it's just too damn challanging and too little motivation :(

I think you misunderstood the challenge. You are given a random number of circles with random coordinates. The progam's task is to read and parse the data, and then calculate the length of the path.

Anyway, back to the challenge. I wasn't able to get to a scanner today, so I'll just type everything up real quick in LaTeX. Stay tuned.
Title: Re: A programming challenge all up in your face.
Post by: TheQuirk on 22 September 2006, 09:58
There. I'll add more stuff to it as we progress. This is actually a dvi file, not a pdf, so change the extension once you download it (the pdf was too large to upload).

[verwijderd door de beheerder]
Title: Re: A programming challenge all up in your face.
Post by: H_TeXMeX_H on 22 September 2006, 22:26
Whoah ... so it's like making a mini CAD program ?!? Damn ... well I give up
Title: Re: A programming challenge all up in your face.
Post by: piratePenguin on 22 September 2006, 23:10
Quote from: H_TeXMeX_H
Whoah ... so it's like making a mini CAD program ?!? Damn ... well I give up
To an extent. But building a mini CAD program would make this challenge pretty simple, and building a mini CAD program would have plenty of uses.
Title: Re: A programming challenge all up in your face.
Post by: worker201 on 22 September 2006, 23:18
Uh, how do I download this file?  Clicking the link causes the browser to handle it as a PDF (which it cannot do).  Trying to save the link target fails as well, because it tries to save attachment.php.  I'm using Firefox, and have had the same problem in Linux and Windows.
Title: Re: A programming challenge all up in your face.
Post by: H_TeXMeX_H on 22 September 2006, 23:51
I can save it, I just don't know what program can view it ...
Title: Re: A programming challenge all up in your face.
Post by: worker201 on 23 September 2006, 00:11
Try a LaTEX reader.  Or run dvips on it to make a PostScript file.  If you have neither, maybe it's update time for you.
Title: Re: A programming challenge all up in your face.
Post by: piratePenguin on 23 September 2006, 00:17
Quote from: H_TeXMeX_H
I can save it, I just don't know what program can view it ...

evince, the GNOME document viewer can. Rename it to .dvi. You might have to install some package to get the DVI support.. I ain't in Ubuntu atm so I can't find it ..

@worker: ALT + click the link to force-save, apparantly. I can't test it here on gnu/linux 'cause alt + click = move window.

If you're on gnu/linux you might need to go into Edit > Prefs > Content > File Types and remove the download action for pdf/whatever
Title: Re: A programming challenge all up in your face.
Post by: H_TeXMeX_H on 23 September 2006, 04:41
Ok, found one ... xdvi. I kept trying tetex, tex, dvi, tetex-dvi, tetex-xdvi, then finally xdvi. (They're not all real I was just trying blindly)
Title: Re: A programming challenge all up in your face.
Post by: mobrien_12 on 23 September 2006, 07:33
kdvi works too.
Title: Re: A programming challenge all up in your face.
Post by: mobrien_12 on 23 September 2006, 23:36
Code: [Select]

## Solution to Quirk's challenge problem
## Written by M O'Brien.  Copyright 2006.
## Licenced to others under GPL.
## Language is GNU Octave ([url]http://www.octave.org[/url])

## READ DATA FILE
fileid=fopen("data.dat","rt");
[x1,count]=fscanf(fileid,"%f",1);
[y1,count]=fscanf(fileid,"%f",1);
[x2,count]=fscanf(fileid,"%f",1);
[y2,count]=fscanf(fileid,"%f",1);
[numcircles,count]=fscanf(fileid,"%d",1);
for k=1:numcircles
  [circledat,count]=fscanf(fileid,"%f %f %f",3);
  circx(k)=circledat(1);
  circy(k)=circledat(2);
  radius(k)=circledat(3);
endfor
fclose(fileid);

##  Start the interesting stuff

linelength=sqrt( (x2-x1)**2 + (y2-y1)**2);
totalpathlength=linelength;
numcirclesintersected=0;
for k=1:numcircles
  ##--------------------------------------------------------------------
  ## calculate distance between circle center and the line.
  numerator=abs((x2-x1)*(y1-circy(k)) - \
(x1-circx(k))*(y2-y1) );
  denominator=sqrt( (x2-x1)**2 + (y2-y1)**2 );
  disttoline=numerator/denominator;
  ##--------------------------------------------------------------------

  if (disttoline < radius(k))
    ## the line is intersecting the current circle, forming a chord.
    ## Only use less than because if it is equal, it is a tangent line
    ## and will not affect the path extension at all
    numcirclesintersected=numcirclesintersected+1;
    halfangle=acos(disttoline/radius(k));
    chordlength=2*radius(k)*sin(halfangle);
    arclength=2*halfangle*radius(k);
    pathdifference=arclength-chordlength;
  else
    ## Line does not interesect the circle.
    pathdifference=0;
  endif
 
  totalpathlength=totalpathlength+pathdifference;

endfor

## final output comes now
disp("total number of circles intersected"),disp(numcirclesintersected);
disp("length of line w/o circles factored in"), disp(linelength);
disp("final path length after circles"), disp(totalpathlength);

fileid=fopen("output.dat","wt");
fprintf(fileid,"%f",totalpathlength);
fclose(fileid);

## end program
Title: Re: A programming challenge all up in your face.
Post by: mobrien_12 on 25 September 2006, 02:45
Thoughts?
Title: Re: A programming challenge all up in your face.
Post by: H_TeXMeX_H on 25 September 2006, 04:58
I dunno, it looks complex enough to work. How do you go about compiling it ?
Title: Re: A programming challenge all up in your face.
Post by: worker201 on 25 September 2006, 05:23
Quote from: mobrien_12
Thoughts?
I'm still trying to figure the math out (and figure out how to download shit that lies about its content in Firefox).  Once that is all over, I should be in a better position to evaluate your program, and perhaps compare it to whatever language mine gets written in (probably perl or C).
Title: Re: A programming challenge all up in your face.
Post by: mobrien_12 on 25 September 2006, 05:53
TeXMeX:  Octave is a scripting language.   All you have to do is put the contents into a file in the same directory as data.dat and call it "linecircles.m" or "kittens.m" or whatever.  

In that directory you would type "octave" on the bash command line and get the octave command line.  Then you would type "linecircles" or "kittens" or whatever and it would run the .m script.

Worker:  The idea of the math is as follows.  Find the distance between the center of the circle and the line, which according to vector analysis is along another line perpendicular to the first line.  If this is less than the radius of the circle then the line intersects the circle.  We then have a right triangle based on the radius to the intersection point and the distance from the center of the circle to the line.  You can use trig to find the angle, and then the length of the original line which we have to remove from the total path length (the chord) because we walk along the edge of the circle instead (the arclength).

From the angle we get the arc length which we add to the totaldistance.

If you subtract the chordlength from the arclength you get the extra path you take from walking around the circle.  You can just add this to the original line length and it makes the code a little more compact.

The attached figure should show some of this.

I'd really like to see this in a compiled language, but Octave is really really good for prototyping math algorithms.

[verwijderd door de beheerder]
Title: Re: A programming challenge all up in your face.
Post by: H_TeXMeX_H on 26 September 2006, 00:41
Hmmm ... just tried it ... seems to work ok.
Title: Re: A programming challenge all up in your face.
Post by: pofnlice on 26 September 2006, 01:02
I can see your lips moving, but I can't hear a word you're saying...
Title: Re: A programming challenge all up in your face.
Post by: worker201 on 26 September 2006, 01:49
Haha, I finally figured out how to download that goddamm thing.  It wasn't nearly as hard as I thought.  Just right click and save as.  I figured that since it was giving me 'attachment.php' that it was some intermediary thing.  But it's the real file.  I don't know why I couldn't get kittens.pdf, but oh well.

Anyway, here's the actual content of the file:
(http://www.triple-bypass.net/download/mathstuff.jpg)
Title: Re: A programming challenge all up in your face.
Post by: H_TeXMeX_H on 26 September 2006, 04:54
Well, then here's the output of kittens.m

Code: [Select]
octave kittens.m
GNU Octave, version 2.9.8 (i686-redhat-linux-gnu).
Copyright (C) 2006 John W. Eaton.
This is free software; see the source code for copying conditions.
There is ABSOLUTELY NO WARRANTY; not even for MERCHANTIBILITY or
FITNESS FOR A PARTICULAR PURPOSE.  For details, type `warranty'.

Additional information about Octave is available at http://www.octave.org.

Please contribute if you find this software useful.
For more information, visit http://www.octave.org/help-wanted.html

Report bugs to (but first, please read
http://www.octave.org/bugs.html to learn how to write a helpful report).

total number of circles intersected
 1
length of line w/o circles factored in
 12.728
final path length after circles
 15.999

it was run with the data.dat containing the original example:
1
10
10
1
1
5 5 4

Looks like it might be working ... I'm just too lazy to check the answer
Title: Re: A programming challenge all up in your face.
Post by: worker201 on 26 September 2006, 07:53
Okay, here's some math that somebody can check for me:

k = slope, u = b-q, r = radius, (p,q) = center of circle
from Quirk's math example:
k^2x^2 + 2kux + u^2 = r^2 -x^2 + 2px - p^2

let j = u^2 - r^2 + p^2, therefore:
k^2x^2 + 2kux + j = -x^2 + 2px
k^2x^2 + x^2 + 2kux -2px + j = 0
x^2(k^2 + 1) + 2x(ku -p) + j = 0

to get it into canonical ax^2 + bx +c form:
let v = k^2 + 1, let w = ku - p, therefore:
vx^2 + 2wx + j = 0

a simple(!) quadratic should finish it from here, giving us values for x in terms of program constants.  If my math is okay.  Anybody want to check it?
Title: Re: A programming challenge all up in your face.
Post by: mobrien_12 on 27 September 2006, 02:56
It does seem to be working, here is some simplified data that I hand calculated

0
0
10
10
1
5 5 1


total number of circles intersected
 1
length of line w/o circles factored in
 14.142
final path length after circles
 15.284


But I do find one problem.  The formula I used for calculating the distance of the circle center from the line is from vector analysis, and assumes the line is actually next to the circle (essentially infinitly long, but defined by two points, and would work with Quirks original data and his original sketch).   In the following case, the program thinks the circle is intercepted, and adds the extra path length for the circle.

This should be fixable in the If statement... any ideas?

[verwijderd door de beheerder]
Title: Re: A programming challenge all up in your face.
Post by: TheQuirk on 27 September 2006, 04:06
I foolighly left my laptop's power adapter in Houston, so I haven't been able to visit the forum much. Anyway, mobrien_12's solution seems spot on (though granted, I don't think he needs my seal of approval :)).

Edit: Saw last message. I don't think you'll be able to do anything without having to revert back to using coordinates.
Title: Re: A programming challenge all up in your face.
Post by: mobrien_12 on 28 September 2006, 03:11
OK, I figured out how to handle the problem.  

Calculate the distance between the endpoint of the line and the center of the circle ("s" in the attached diagram).  We already know the distance from the circle center to the line (or it's infinite extension) ("d" in the diagram).  We find the projection of "s" along the line ("p" in the diagram) using simple trig (we have a right triangle).  If the projection is longer than the line, the circle center is not next to the line and we discard it.  If, as shown in the figure, the projection is shorter than the line, then the circle is actually next to the line and there is no problem.

But in thinking up this solution I realized that the original challenge was missing one specification.  What to do if the line goes into the circle but does not come out?
In other words, what if an endpoint is located within one of the circles?

I say we should ignore the circle in that particular case because we don't have both the beginning and end points are defined on it to tell us the path to take when walking around the edge.

[verwijderd door de beheerder]
Title: Re: A programming challenge all up in your face.
Post by: worker201 on 28 September 2006, 05:48
I was thinking about this earlier.  I was going to include a simple test in my version.  Once I know the 2 points where the line intersects the circle, I will test the x values with relation to the x values on my line.  Given that a straight line has a 1 to 1 relationship between the domain and the range.  For example, let's say my line runs from (5,2) to (25,8).  If one of the x values of the intersection points is > 25 or < 5, then we know that the line segment of interest enters the circle but does not leave it (even though the infinitely extended line does).  At that point, I agree, the circle should be discarded.

Currently, my biggest challenge is figuring out how to separate the input.  Your Octave program uses a loop inside the filestream to assign the data to the variables. I just have to figure out how to do that in C (my C-skills are kinda weak).
Title: Re: A programming challenge all up in your face.
Post by: worker201 on 28 September 2006, 10:43
Meh, having some trouble with the beginning of the program.  All I have so far is the code to read the data, and then print it, to verify it is working.  But it doesn't work.
 
Code: [Select]
#include
#include

main()
{

const float pi=3.14159;
FILE *fRead;
char filename[20];
float x1, y1;
float x2, y2;
int i, numcirc;
float circlex[15], circley[15], radius[15];

fRead = fopen("file1.dat", "r");
if (fRead==NULL) {
printf("File unavailable\n");
return 1;
}
fscanf(fRead, "%f", x1);
fscanf(fRead, "%f", y1);
fscanf(fRead, "%f", x2);
fscanf(fRead, "%f", y2);
fscanf(fRead, "%d", numcirc);
if (numcirc>15) {
printf("too many circles, aborting\n");
return 1;
}
for(i=0; i fscanf(fRead, "%f%f%f", circlex[i], circley[i], radius[i]);
}
fclose(fRead);

printf("x1 is %f\n", x1);
printf("y1 is %f\n", y1);
printf("x2 is %f\n", x2);
printf("y2 is %f\n", y2);
printf("numcirc is %d\n", numcirc);
printf("circles:\n");
for(i=0; i printf("%f %f %f", circlex[i], circley[i], radius[i]);
}
printf("That's all the data I got/n");
return 0;

}
If the file doesn't exist, it prints "file unavailable" and exits, like I expected.  But if the file does exist, all I get is "Bus error".  Compiling and running on a Mac.  Any ideas?  I've never used file pointers or file streams before, so that's probably where the problem is.

Also, is there a way to get around setting the size of my arrays?  I would rather just have radius[] be open, so I could process any number of circles.  But declaring them without a size gives a syntax error.
Title: Re: A programming challenge all up in your face.
Post by: mobrien_12 on 28 September 2006, 16:45
The problem is the fscanf statements.  

You have this format

fscanf(fid, formatstring, variable)

You need

fscanf(fid, formatstring, &variable)
Title: Re: A programming challenge all up in your face.
Post by: pofnlice on 28 September 2006, 17:18
(http://www.forumspile.com/Emoticons/Explode.gif)
Title: Re: A programming challenge all up in your face.
Post by: H_TeXMeX_H on 28 September 2006, 23:16
[offtopic] Yeah, that's why I don't like to use C++ for non-important programs that you wanna make work fast. It usually takes a decent amount of debugging to get working, and it's just things so obscure that you don't notice them EVEN WHILE STARING AT THEM !!! Usually the best thing is to get someone else to check your code, like I did often in my computer science class. I usually use bash, cuz it's convenient, and I don't care about portability to Window$ ... all unix based OSs such as Linux, Solaris, BSD have a bourne compatible shell ... easy

P.S. That's a really cool smiley (http://www.forumspile.com/Emoticons/Explode.gif)[/offtopic]
Title: Re: A programming challenge all up in your face.
Post by: pofnlice on 28 September 2006, 23:21
I gots skillz!(http://www.forumspile.com/Emoticons/Ninja-Invisible.gif)

(http://www.forumspile.com/Emoticons/Poke.gif)

(http://www.forumspile.com/Emoticons/Mexican_wave.gif)

(http://www.forumspile.com/Emoticons/Emoticons-Thread_recap.gif)
Title: Re: A programming challenge all up in your face.
Post by: H_TeXMeX_H on 28 September 2006, 23:27
(http://www.forumspile.com/Emoticons/Shoot-from_left.gif)(http://www.forumspile.com/Emoticons/Mexican_wave.gif)(http://www.forumspile.com/Emoticons/Shoot-from_right.gif)

(http://www.forumspile.com/Emoticons/Shoot-Right_wins.gif)
Title: Re: A programming challenge all up in your face.
Post by: mobrien_12 on 29 September 2006, 01:22
Quote from: pofnlice
(http://www.forumspile.com/Emoticons/Explode.gif)

Oh my god, we killed Kenny!
Title: Re: A programming challenge all up in your face.
Post by: mobrien_12 on 29 September 2006, 01:47
Quote from: H_TeXMeX_H
[offtopic] Yeah, that's why I don't like to use C++ for non-important programs that you wanna make work fast. It usually takes a decent amount of debugging to get working, and it's just things so obscure that you don't notice them EVEN WHILE STARING AT THEM !!![/offtopic]


[offtopic]
One of the reasons I like Octave for prototyping is that it is easy to work with, that and it's just really really powerful for math.  It has a lot of support for math that other languages just dont.

I've done huge code prototypes on Octave that would have probably taken twice the time or maybe been impossible with my skills to prototype directly on C.

But you can't beat compiled code for overall performance.  When I was in grad school, there was this guy who was running lots of number crunching for his thesis.  He used matlab, but his computations were so heavy that he ended up going to the computer lab and monopolizing 3-4 computers for several hours at a time, over months, just running them all in parallel grinding matlab.  If he stopped being lazy, and turned his code into C, he would have been able to crunch the code so much faster and on one machine.

By the way, Bash works very well on WindowsXP through Cygwin.  I think I'd be going freaking insane without it.

[/offtopic]
Title: Re: A programming challenge all up in your face.
Post by: H_TeXMeX_H on 29 September 2006, 02:28
[offtopic]Oh yeah Cygwin ... I forgot about that.[/offtopic]
Title: Re: A programming challenge all up in your face.
Post by: worker201 on 29 September 2006, 23:49
Okay, so I have a version that appears to be working.  Quick question, though: we know that if the discriminant of the quadratic equation is less than zero, the line and the circle don't intersect.  If it is greater than zero, then the line and circle do intersect, at the solution points.  What happens if the discriminant equals zero?  That means there is one solution, or rather, 2 identical solutions.  Doesn't this mean that the line is vertical?

Furthermore, how should we deal with vertical lines?  If the x-coordinates are identical, the slope will be undefined.  I guess I have to include a couple more if statements.
Title: Re: A programming challenge all up in your face.
Post by: H_TeXMeX_H on 30 September 2006, 00:38
if the descriminant is 0 then there is one root meaning that the line is tangent to the circle (it touches the circle at a single point ... rare indeed)
Title: Re: A programming challenge all up in your face.
Post by: worker201 on 30 September 2006, 01:09
Quote from: H_TeXMeX_H
if the descriminant is 0 then there is one root meaning that the line is tangent to the circle (it touches the circle at a single point ... rare indeed)

How could you tell?  I think you would get the same solution for a tangent or for a vertical line.

Anyway, my program cannot handle vertical lines yet. Or tangents.
Title: Re: A programming challenge all up in your face.
Post by: H_TeXMeX_H on 30 September 2006, 03:43
Hmmm ... yeah, this is too damn hard.
Title: Re: A programming challenge all up in your face.
Post by: worker201 on 30 September 2006, 04:06
Why am I unable to post my code?
Quote
Not Acceptable

 An appropriate representation of the requested resource /forums/editpost.php could not be found on this server.
Title: Re: A programming challenge all up in your face.
Post by: mobrien_12 on 30 September 2006, 08:00
There's some stupid bug in the system if you have a couple of characters one right after the other the whole post gets borked.  I can't remember the sequence... we had a thread on it last year, but it never got fixed.

Try posting chunks of it with edit to find out what is crashing the system.  That's what I had to do last time one of my posts triggered this bug.

Alternatatively you could compress and upload it as a tgz or bz2 file.

Please do it, I want to see the code :)
Title: Re: A programming challenge all up in your face.
Post by: TheQuirk on 30 September 2006, 11:03
Wow, this thread has taken off.

Re: vertical lines, since we have this:

[(y2 - y1)/(x2 - x1)]x + k = y

We could multiply both sides by (x2 - x1) and see what that gets us (there won't be division by 0).

Re: Matlab, I was always under the impression that Matlab could actually do lots of computations faster than compiled C.
Title: Re: A programming challenge all up in your face.
Post by: H_TeXMeX_H on 30 September 2006, 19:01
Quote from: worker201
Why am I unable to post my code?

The keyword you can't post is:

f  open

So why can I post it ? Because there are two spaces between f and open instead of one :)
Title: Re: A programming challenge all up in your face.
Post by: mobrien_12 on 30 September 2006, 21:14
Quote from: H_TeXMeX_H
The keyword you can't post is:

f  open

So why can I post it ? Because there are two spaces between f and open instead of one :)


But I could post fopen??

f opan
f op
f ope
f opep
g open

but f with a space followed by open barfs the system.

WTF kind of bug is this?
Title: Re: A programming challenge all up in your face.
Post by: piratePenguin on 30 September 2006, 21:20
mobrien: put a space between the f and open. Using two spaces works, ala: f  open
Quote
Not Acceptable
An appropriate representation of the requested resource /forums/editpost.php could not be found on this server.


That is a classy error message if ever I saw one.
Title: Re: A programming challenge all up in your face.
Post by: mobrien_12 on 30 September 2006, 21:23
OK this bug needs to be a sticky somewhere.
Title: Re: A programming challenge all up in your face.
Post by: mobrien_12 on 30 September 2006, 21:32
Quote from: TheQuirk

Re: Matlab, I was always under the impression that Matlab could actually do lots of computations faster than compiled C.


Certain matrix calculations yes, because it has optimized compiled libraries that take care of them.  It has superior support or complex numbers as well.

In general, however, for very large codebases, it's slow as a basset hound on a hot summer day after eating a steak.  It is a scripting language.  

You need to be a pretty experienced Matlab or Octave coder to be able to take advantage of the vector/matrix nature of the languages properly, and that will help, but if you want to speed up the calculations you need to either recode in C or Fortran 9x or take the slowest parts of the code base and turn those into C.  You can link compiled C code into Matlab or Octave, and that speeds things up a hell of a lot, but that requires you to not be a lazy bastard.

There is a Matlab compiler now... not sure how its performance compares to C.
Title: Re: A programming challenge all up in your face.
Post by: piratePenguin on 30 September 2006, 21:32
just testing.
testing
Title: Re: A programming challenge all up in your face.
Post by: worker201 on 1 October 2006, 04:57
I didn't understand M_Obrien's geometry, so I used the Law of Cosines.  As displayed in the following image:
(http://www.triple-bypass.net/download/lawcosines.png)

I can't deal with tangent lines, vertical lines, or datfiles with more than 16 circles.  Otherwise, it seems to work fine.

http://www.triple-bypass.net/download/circleline.txt
Title: Re: A programming challenge all up in your face.
Post by: mobrien_12 on 1 October 2006, 08:09
Updated solution to fix the problem mentioned before.  

Code: [Select]

## Solution to Quirk's challenge problem Version 2
## Written by M O'Brien.  Copyright 2006.
## Licenced to others under GPL.
## Language is GNU Octave (http://www.octave.org)

## READ DATA FILE
fileid=fopen("data.dat","rt");
[x1,count]=fscanf(fileid,"%f",1);
[y1,count]=fscanf(fileid,"%f",1);
[x2,count]=fscanf(fileid,"%f",1);
[y2,count]=fscanf(fileid,"%f",1);
[numcircles,count]=fscanf(fileid,"%d",1);
for k=1:numcircles
  [circledat,count]=fscanf(fileid,"%f %f %f",3);
  circx(k)=circledat(1);
  circy(k)=circledat(2);
  radius(k)=circledat(3);
endfor
fclose(fileid);

##  Start the interesting stuff

linelength=sqrt( (x2-x1)**2 + (y2-y1)**2 );

totalpathlength=linelength;
numcirclesintersected=0;
for k=1:numcircles
 
  ## calculate distace from the line to the center of circle
  ## formula is from vector analysis but can be found with web
  ## search
 
  numerator=abs((x2-x1)*(y1-circy(k)) - \
(x1-circx(k))*(y2-y1) );
  disttoline=numerator/linelength;
 
  ## define some intermediate variables to make later equations readable
  ## s1 is distance from line endpoint 1 to center circle
  s1=sqrt( (circx(k)-x1)**2 + (circy(k)-y1)**2 );
  ## s2 is distance from line endpoint 2 to center circle
  s2=sqrt( (circx(k)-x2)**2 + (circy(k)-y2)**2 );
  ## p1 is the projection of s1 along the line (vector component)
  p1=sqrt( s1**2 - disttoline**2 );
  ## p2 is the projection of s2 along the line (vector component)
  p2=sqrt( s2**2 - disttoline**2 );
 
 
  ## these are boolean, true or false
  ## check to see if a line endpoint is inside the circle
  EndInCircle= ( ( s1 < radius(k) ) | ( s2 < radius(k) ) );
  LineInRange= (disttoline < radius(k));
  LineLongEnough = ( ( p1 < linelength ) & ( p2 < linelength ) );

  if ( (!EndInCircle) & (LineInRange) & (LineLongEnough) )
    ## the line is intersecting the current circle, forming a chord.
    ## Only use less than because if it is equal, it is a tangent line
    ## and will not affect the path extension at all
    numcirclesintersected=numcirclesintersected+1;
    halfangle=acos(disttoline/radius(k));
    chordlength=2*radius(k)*sin(halfangle);
    arclength=2*halfangle*radius(k);
    pathdifference=arclength-chordlength;
  else
    ## Line does not interesect the circle.
    pathdifference=0;
  endif
 
  totalpathlength=totalpathlength+pathdifference;

endfor

## final output comes now
disp("total number of circles intersected"),disp(numcirclesintersected);
disp("length of line w/o circles factored in"), disp(linelength);
disp("final path length after circles"), disp(totalpathlength);

fileid=fopen("output.dat","wt");
fprintf(fileid,"%f",totalpathlength);
fclose(fileid)

## end program


Tested with the following data.
Code: [Select]

0
0
10
10
2
5 5 1
20 20 2


With the following results
Quote

total number of circles intersected
 1
length of line w/o circles factored in
 14.142
final path length after circles
 15.284



Actual answer is 15.28372827

Final answer is rounded off to 3 decimal places so the answer is fully correct.
Title: Re: A programming challenge all up in your face.
Post by: mobrien_12 on 1 October 2006, 08:22
Worker, I tried to compile your code but get errors.... it says sqrt and acos is undefined.  

I just did gcc circleline.c, and I do have math.h on my system.  Do I need a special library?

EDIT:  nevermind... forgot about the -lm to link to the math library....
Title: Re: A programming challenge all up in your face.
Post by: mobrien_12 on 1 October 2006, 08:32
Output from Worker's program.
Quote

15.282185


Actual answer is 15.28372827

Looks good!
Title: Re: A programming challenge all up in your face.
Post by: worker201 on 1 October 2006, 08:47
I noticed that too.  At what stage do our calculation differences come from?
Title: Re: A programming challenge all up in your face.
Post by: H_TeXMeX_H on 1 October 2006, 17:50
Well you used float for all your numbers (not recommended), might wanna use double for better precision.
Title: Re: A programming challenge all up in your face.
Post by: cymon on 1 October 2006, 17:58
If I understood this math, I would probably get the challenge.
Title: Re: A programming challenge all up in your face.
Post by: worker201 on 1 October 2006, 20:15
Could be.  acos, sqrt, and pow all return doubles, so the program is probably running some internal float>>double conversions in a few places.
Title: Re: A programming challenge all up in your face.
Post by: H_TeXMeX_H on 1 October 2006, 22:52
Yeah, something like that ... I always use double for any non-integer.
Title: Re: A programming challenge all up in your face.
Post by: mobrien_12 on 2 October 2006, 04:05
It would be interesting to see if it gets more decimal places correct using double precision.

As it is, there's only 0.1% error.
Title: Re: A programming challenge all up in your face.
Post by: mobrien_12 on 2 October 2006, 08:43
Quote from: TheQuirk
Wow, this thread has taken off.

Re: vertical lines, since we have this:

[(y2 - y1)/(x2 - x1)]x + k = y

We could multiply both sides by (x2 - x1) and see what that gets us (there won't be division by 0).


Been thinking about this.  You could do this but for a vertical line you are multiplying both sides by zero then, which gets you down to the fundamental problem:  a vertical line segment is not a function of x.  The entire coordinate-type algorithm is based around y being a function of x so it falls apart at this case.

The vector-analysis algorithm that I used doesn't need y to be a function of x.  

This doesn't mean that the coordinate-type algorithm can't do it.

Just test to see if it is a vertical line.  If so, then simply rotate the coordinate system by 90 degrees and you have a horizontal line.  Then the algorithm will work.
Title: Re: A programming challenge all up in your face.
Post by: worker201 on 3 October 2006, 01:24
Would it be ghetto to write a whole other routine just for dealing with verticals?  It's a much easier task.  Say our vertical line was x=5.  You could just plug that into the circle equation and solve for y.  If you get 2 different real y values, then the circle intersects the line, and you can continue from there.  It would probably be more elegant to write the routine in a way that didn't depend on the slope of the line (or distinct functions of variables), but I think for something as simple and specific as this, maybe a case solution might be better.

WWAD?
(what would Adobe do?)
:P
Title: Re: A programming challenge all up in your face.
Post by: mobrien_12 on 3 October 2006, 03:37
Quote from: worker201
Would it be ghetto to write a whole other routine just for dealing with verticals?  It's a much easier task.  Say our vertical line was x=5.  You could just plug that into the circle equation and solve for y.  If you get 2 different real y values, then the circle intersects the line, and you can continue from there.  It would probably be more elegant to write the routine in a way that didn't depend on the slope of the line (or distinct functions of variables), but I think for something as simple and specific as this, maybe a case solution might be better.

WWAD?
(what would Adobe do?)
:P


Eh, simplest solution is the best I guess. I was just trying to think of how to make the existing code work for the one special case... I thought that would be the easiest.  If a second routine to handle it would be easier, it's probably better to go that way...
Title: Re: A programming challenge all up in your face.
Post by: TheQuirk on 3 October 2006, 18:41
Quote from: mobrien_12
Been thinking about this.  You could do this but for a vertical line you are multiplying both sides by zero then, which gets you down to the fundamental problem:  a vertical line segment is not a function of x.  The entire coordinate-type algorithm is based around y being a function of x so it falls apart at this case.

The vector-analysis algorithm that I used doesn't need y to be a function of x.  

This doesn't mean that the coordinate-type algorithm can't do it.

Just test to see if it is a vertical line.  If so, then simply rotate the coordinate system by 90 degrees and you have a horizontal line.  Then the algorithm will work.


Aye, the point is that you would get (y2-y1) + k(x2-x1) = y(x2-x1) => y2-y1 = 0 which is obviously false, thus pointing out that it's a vertical line. This is how we generally solved problems which involved coordinates.

(For what it's worth, however, I think your method is a lot nicer.)
Title: Re: A programming challenge all up in your face.
Post by: mobrien_12 on 4 October 2006, 06:14
But I really like the idea that we have two completely different solutions which give the same answers!!!  And the code base is about the same length for each!

And you notice how that the challenge was put down a few months ago, but when we all worked together we knocked it out in a week or so? This has really been FUN!

I was able to fix the special cases in my approach that messed it up, maybe this weekend we can fix the vertical line case in the coordinates! :)
Title: Re: A programming challenge all up in your face.
Post by: worker201 on 4 October 2006, 06:20
Just started my new job, so I haven't had much spare time to mess with this yet.  But I have a plan to deal with vertical lines and tangents that I think will be cool.  I also want to recast everything as doubles, just to see what the change is.
Title: Re: A programming challenge all up in your face.
Post by: mobrien_12 on 5 October 2006, 05:27
#include
#include
#include
#define TRUE 1
#define FALSE 0

int main()
{
  /* variable declarations */
 
  /* file read/write variables */
 
  typedef int bool;
  bool transpose;
  /* temporary "shuffle" variable used to transpose coordinates */
  float tempcoord;
  /* variables declared from input */
  float x1, y1, x2, y2;
  int i, numcirc;
  float circlex[15], circley[15], radius[15];
  /* variables for internal use */
  float slope, yint, rsquare, discrim, theta;
  float aterm, bterm, cterm;
  float u, j, v, w, high, low;
  float total, chord, arc;
  float intx1[15], intx2[15], inty1[15], inty2[15];
Title: Re: A programming challenge all up in your face.
Post by: mobrien_12 on 5 October 2006, 05:38
Modified worker's program to take care of vertical lines... the tangent's still need to be done.  Don't think I can do that...

It works :)

Tested with this data
Code: [Select]

5
0
5
10
2
5 5 1
20 20 2


CAN'T POST THE CODE..... CAN'T FIGURE OUT WHAT'S MAKING IT BARF.... there's no f  open in there.

GAH

I left some troubleshooting printf statements in there.... sorry it's getting late.  I also commented out the scanfs becasue I didn't want to type in the file names while troubleshooting... easy enought to uncomment them.

[verwijderd door de beheerder]
Title: Re: A programming challenge all up in your face.
Post by: Lead Head on 5 October 2006, 22:20
Wow
Title: Re: A programming challenge all up in your face.
Post by: worker201 on 7 October 2006, 09:13
What an exciting Friday night, programming in C.  :cool:

Here's my latest version:
http://www.triple-bypass.net/download/circleline2.txt

It deals with vertical lines and tangents, and even has a function!

Too bad it doesn't work.

For some reason, my logically flawless method of catching tangents doesn't seem to work.  Here's the data I tested with:
0
5
10
5
1
5 6 1

Overall, the whole program doesn't work.  It ends up writing "nan" to the output file.  Which makes me think that there is something really screwy going on.  Notice that all the floats are now doubles - could that be to blame?  Or maybe it's the function not returning properly.  Honestly, the thing I find most difficult about programming, by far, is understanding variable scope.  It seems like it would be so much easier to just have the function use the same variables the program does.  Any suggestions?
Title: Re: A programming challenge all up in your face.
Post by: TheQuirk 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.
Title: Re: A programming challenge all up in your face.
Post by: mobrien_12 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
Title: Re: A programming challenge all up in your face.
Post by: worker201 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.
Title: Re: A programming challenge all up in your face.
Post by: mobrien_12 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.   :)
Title: Re: A programming challenge all up in your face.
Post by: TheQuirk 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);
   }
Title: Re: A programming challenge all up in your face.
Post by: mobrien_12 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...
Title: Re: A programming challenge all up in your face.
Post by: worker201 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.
Title: Re: A programming challenge all up in your face.
Post by: H_TeXMeX_H 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).
Title: Re: A programming challenge all up in your face.
Post by: mobrien_12 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);

Title: Re: A programming challenge all up in your face.
Post by: mobrien_12 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.
Title: Re: A programming challenge all up in your face.
Post by: worker201 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.
Title: Re: A programming challenge all up in your face.
Post by: worker201 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 (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.
Title: Re: A programming challenge all up in your face.
Post by: mobrien_12 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???
Title: Re: A programming challenge all up in your face.
Post by: worker201 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.
Title: Re: A programming challenge all up in your face.
Post by: mobrien_12 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.
Title: Re: A programming challenge all up in your face.
Post by: H_TeXMeX_H on 12 October 2006, 00:04
Much better, good job.
Title: Re: A programming challenge all up in your face.
Post by: worker201 on 13 October 2006, 00:47
What happens when the decimal point error occurs in the other direction?  Meaning, what if we got -0.99999999999999934442 instead of -1?  Didn't happen in this particular case, but I bet it could.

I think a momentary recast of the argument sent to acos would work better.  Wouldn't have to change all the variables, just that one.  The return from acos will be a double no matter what value you give it.  So why not make it a value with acceptable precision?
Title: Re: A programming challenge all up in your face.
Post by: mobrien_12 on 14 October 2006, 04:06
Quote from: worker201
What happens when the decimal point error occurs in the other direction?  Meaning, what if we got -0.99999999999999934442 instead of -1?  Didn't happen in this particular case, but I bet it could.

I think a momentary recast of the argument sent to acos would work better.  Wouldn't have to change all the variables, just that one.  The return from acos will be a double no matter what value you give it.  So why not make it a value with acceptable precision?


Yup, but it will just be imprecision then, tiny tiny numerical error.  If the absolute value gets greater than one it's tragic because it breaks the trig function.  

Nothing wrong with error creating a tiny bit of imprecision, it will be smaller than the decimals you see with single precision...we just have to sanity check the data to make sure it doesn't break something.  Your stuff works! :)

Now does it work with tangents and vertical lines?
Title: Re: A programming challenge all up in your face.
Post by: worker201 on 14 October 2006, 08:11
Hahahaha, rockstar = me.

Okay, here's the latest fully operational version of the circleline program:
http://www.triple-bypass.net/download/circleline3.txt (http://www.triple-bypass.net/download/circleline3.txt)

It has been cleaned up a bit - at first it made sense to document every step of the messy quadratic equation.  Now, extraneous assignments and variables have been removed.  The calculation of circle arcs and the calculation of distances are both functions, and instead of returning a variable, they return an expression - again, removing unnecessary steps that were once invaluable.

The decimal point error has been corrected, and I am now getting nice accurate values with doubles.  Here's the method:
Code: [Select]
double theta;
double rsquare;
double arc;
float stepone;

rsquare = pow(rad, 2);
stepone = (2 * rsquare - pow(chord, 2)) / (2 * rsquare);
theta = acos(stepone);
By declaring stepone, the argument passed to acos, as a float, I forced the Cosine Law calculation to return a float.  Since all the variables in the equation are doubles, the result is automatically a double.  Because of the declaration, however, the result is converted into a float.  The result is that the double value is truncated to float precision.  Even if you viewed the value of stepone (in the testfile) to 25 places, it is still just -1.  stepone then gets converted back to a double when it is passed to acos.  As you will see below, the results are great.

Also, since the results of acos are precise enough to pass the "== 0" test, my tangent-catcher works.  And vertical lines are handled appropriately, using the calcarc and distancer function just as well as the normal lines.  Horizontal lines are also dealt with appropriately.

Results:

1. normal test case
file1.dat:
Code: [Select]
0
0
10
10
1
5 5 1
Code: [Select]
powbook:~ lholcombe$ ./a.out
Enter a filename for input:
file1.dat
circle # 1 intersects the line, calculating arc distance
Enter a filename for output:
file1.out
file1.out:
Code: [Select]
15.2837
2. horizontal line with tangent circle

file2.dat:
Code: [Select]
0
5
10
5
1
5 6 1
Code: [Select]
powbook:~ lholcombe$ ./a.out
Enter a filename for input:
file2.dat
circle # 1 does not intersect the line (tangent)
Enter a filename for output:
file2.out
file2.out:
Code: [Select]
10
3. vertical line with intersecting circle

file3.dat:
Code: [Select]
0
0
0
10
1
0 5 1
Code: [Select]
powbook:~ lholcombe$ ./a.out
Enter a filename for input:
file3.dat
circle # 1 intersects the line, calculating arc distance
Enter a filename for output:
file3.out
file3.out:
Code: [Select]
11.1416
If anyone has any sensible suggestions for improving this program, please offer them.
Title: Re: A programming challenge all up in your face.
Post by: mobrien_12 on 14 October 2006, 08:50
Aces!  Two completely different solutions in two different languages for the same problem with the same answer :)
Title: Re: A programming challenge all up in your face.
Post by: solemnwarning on 14 October 2006, 14:19
Quote from: mobrien_12
Aces!  Two completely different solutions in two different languages for the same problem with the same answer :)


Thats the UNIX way!
Title: Re: A programming challenge all up in your face.
Post by: worker201 on 14 October 2006, 17:31
So where's the next problem to program?
Title: Re: A programming challenge all up in your face.
Post by: piratePenguin on 14 October 2006, 17:49
Quote from: worker201
So where's the next problem to program?

Make a CAD program, methinks.
Title: Re: A programming challenge all up in your face.
Post by: worker201 on 14 October 2006, 17:53
Did ya happen to notice that it took like 3 weeks to produce a 175 line program?  How long do you think a CAD program would take?
Title: Re: A programming challenge all up in your face.
Post by: H_TeXMeX_H on 14 October 2006, 18:54
Well, it doesn't always take that long to make a program (especially if you're not using C or C++). Like it took me 4-6 hours to make a shell script (360 lines or more) that I could use to manage the installation of things like OpenOffice and Firefox which aren't available from the FC repo, or if they are available they are broken or fucked up versions. I also helps bypass some of the dependency problems of RPM.
Title: Re: A programming challenge all up in your face.
Post by: piratePenguin on 14 October 2006, 19:15
Wow.. I just went through my old (old) programming crap and found the start I made to this challenge.. and it ain't bad! Dated 05-Feb-2006. Jesus I can't believe this!

http://piratepenguin.is-a-geek.com/~declan/crap/old-stuff/programming/c/curve_challenge/main.c or http://illhostit.com/files/cd815a8f0c8a59847303fe1067003ab0/main.c

It uses glib (linked lists FTW!), so install glib2.0-dev or whatever and compile with: 'gcc main main.c `pkg-config --cflags --libs glib-2.0` -lm'. (WTF: o with a hyphen (-) before it triggers that Forbidden message bug crap)

(it prints the INPUT, and records to stdout and to OUTPUT)
Quote
[declan@localhost curve_challenge]$ ./main
line.p1.x: 0
line.p1.y: 0
line.p2.x: 10
line.p2.y: 10
num_circles: 1

circle->c.x: 5
circle->c.y: 5
circle->r: 1

The length of the curve is: 14.142136  [proper answer is apparently 15.2837]

 -- modify input --

[declan@localhost curve_challenge]$ ./main
line.p1.x: 0
line.p1.y: 5
line.p2.x: 10
line.p2.y: 5
num_circles: 1

circle->c.x: 5
circle->c.y: 6
circle->r: 1

The length of the curve is: 10.000000

 -- modify input --

[declan@localhost curve_challenge]$ ./main
line.p1.x: 0
line.p1.y: 0
line.p2.x: 0
line.p2.y: 10
num_circles: 1

circle->c.x: 0
circle->c.y: 5
circle->r: 1

The length of the curve is: 10.000000
Hehheh the tangent stuff works! (I think that's the *only* time it gets it right.. It wasn't complete and I don't feel like completing it, and the bits I don't have are probably the hardest - and why I never bothered to finish it)

Maybe it doesn't work with multiple circles either.. I should comment more heh.
Quote
[declan@localhost curve_challenge]$ ./main
line.p1.x: 5
line.p1.y: 0
line.p2.x: 5
line.p2.y: 10
num_circles: 2

circle->c.x: 5
circle->c.y: 5
circle->r: 1

circle->c.x: 20
circle->c.y: 20
circle->r: 2

The length of the curve is: 10.000000
Is that right/wrong?
Title: Re: A programming challenge all up in your face.
Post by: mobrien_12 on 14 October 2006, 20:13
Penguin, your code seems to be calculating the lines alone and ignoring all the circles.  

You could finish it... :)
Title: Re: A programming challenge all up in your face.
Post by: piratePenguin on 14 October 2006, 20:23
Quote from: mobrien_12
Penguin, your code seems to be calculating the lines alone and ignoring all the circles.  

You could finish it... :)
Yeah, well, it doesn't do a bad job of it! :p

I looked a bit at the code, and it hurts my eyes, and unfortunetly I don't have time for that anymore :(
Title: Re: A programming challenge all up in your face.
Post by: mobrien_12 on 15 October 2006, 09:03
Ok, now that I got Worker to figure out all the problems that might arise in C for me :)

Here's the vector solution in C.. some of his code blatently ripped off :)


Code: [Select]

/*
   vectsoln.c Vector solution in C form
*/

#include
#include
#include
#define TRUE 1
#define FALSE 0
#define FILENAMELENGTH 40
int main()
{
  /* variable declarations */
 
  /* file read/write variables */
  FILE *fRead;
  FILE *fWrite;
  char infilename[FILENAMELENGTH];
  char outfilename[FILENAMELENGTH];
  /* boolean variable type defined */
  typedef int bool;
   
  /* variables declared from input */
  double x1, y1, x2, y2;
  int i, numcircles;
  double circx[15], circy[15], radius[15];
 
  /* variables of importance */
  double linelength, totalpathlength;
  int numcirclesintersected=0;
 
  /* booleans of interest */
  bool EndNotInCircle, LineInRange, LineLongEnough;

  /* variables for intermediate calculations */
  double s1,s2,p1,p2,disttoline,numerator;
   
  double halfangle, arclength, chordlength, pathdifference;
 
  /* opening the file and reading contents into variables */
  /* printf("Enter a filename for input:\n");
    scanf("%s", &infilename); */
  strncpy(infilename,"data.dat",40);
  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", &numcircles);
  printf("x1 %f y1 %f x2 %f y2 %f numcircles %i\n",x1,y1,x2,y2,numcircles);
   
  if (numcircles>15)
    {
    printf("too many circles, aborting\n");
    return 1;
    }
  else
    {
    printf("%i circles in file.\n",numcircles);
    for(i=0; i      {
printf("loading circle %i\n",i);
fscanf(fRead, "%lf%lf%lf", &circx[i], &circy[i], &radius[i]);
printf("circledata x %f y %f r %f \n",circx[i],circy[i],radius[i]);
      }
    }

  fclose(fRead);

  /* finished loading data (whew) Start interesting stuff */
 
  linelength = sqrt(pow(x2-x1, 2) + pow(y2-y1, 2));
  totalpathlength=linelength;
  for (i=0; i    {
      numerator=fabs( (x2-x1)*(y1-circy[i]) - (x1-circx[i])*(y2-y1) );
      disttoline= numerator/linelength;
      s1=sqrt( pow((circx[i]-x1),2) + pow((circy[i]-y1),2) );
/* s2 is distance from line endpoint 2 to center circle */
      s2=sqrt( pow((circx[i]-x2),2) + pow((circy[i]-y2),2) );
/* p1 is the projection of s1 along the line (vector component) */
      p1=sqrt( pow(s1,2) - pow(disttoline,2) );
/*  p2 is the projection of s2 along the line (vector component) */
      p2=sqrt( pow(s2,2) - pow(disttoline,2) );
   

if  ( ( s1 < radius[i] ) || ( s2 < radius[i] ) )
 {
   EndNotInCircle=FALSE;
 }
else
 {
   EndNotInCircle=TRUE;
 }

if ( disttoline < radius[i] )
 {
   LineInRange = TRUE;
 }
else
 {
   LineInRange = FALSE;
 }

if  ( ( p1 < linelength ) && ( p2 < linelength ) )
 {
   LineLongEnough=TRUE;
 }
else
 {
   LineLongEnough=FALSE;
 }

/* key conditional for intersecting a circle */
if (EndNotInCircle==TRUE && LineInRange==TRUE && LineLongEnough==TRUE)
 {
   numcirclesintersected++;
   halfangle=acos(disttoline/radius[i]);
   chordlength=2*radius[i]*sin(halfangle);
   arclength=2*halfangle*radius[i];
   pathdifference=arclength-chordlength;
 }
else
 {
   pathdifference=0;
 }
 
totalpathlength=totalpathlength+pathdifference;

    }

  printf("Total number of circles intersected: %d\n",numcirclesintersected);
  printf("Original path Length %f\n",linelength);
  printf("Final path Length %f\n",totalpathlength);
  /* writing the output to a file */
  /**printf("Enter a filename for output:\n");
     scanf("%s", &outfilename);*/
  strncpy(outfilename,"out.dat",40);
  fWrite = fopen(outfilename, "w");
  if (fWrite==NULL)
    {
      printf("output file unavailable\n");
      return 1;
    }
  fprintf(fWrite, "%f\n", totalpathlength);
  fclose(fWrite);
 
  return 0;
 
}


Quote from: data

0
0
10
10
2
5 5 1
20 20 2


Quote from: result

Total number of circles intersected: 1
Original path Length 14.142136
Final path Length 15.283728