Link to home
Start Free TrialLog in
Avatar of joedfuse
joedfuseFlag for United States of America

asked on

c++ sub program and functions

Hello all,

Im in the process of learning c++ and I wrote the following code to randomly generate some points, calculate the distance and diameter and finally use a decision statement to tell if the line is inside a circle. ALL MY CODE WORKS fine. What I cant figure out how to do is break the code up into sub programs. Obviously it doesnt have to be split up but I want to learn to use functions and arguments. As you can see I prototyped 3 functions above the main(). Somehow I have to create the functions and use them in the main function to out put the values as its currently laid out. Thanks in advance for any help you can provide.

#include <iostream>
#include <cstdlib>
#include <cmath>
#include <ctime>

using namespace std;

// below are the prototypes

double randomDouble(const double& from, const double& to);

double lineSegLen(const float& lp0x, const float& lp0y, const float& lp1x, const float& lp1y);

bool lineInCircle(const float& lp0x, const float& lp0y, const float& lp1x, const float& lp1y, const float& cmpx, const float& cmpy, const float& radius);

int main ()             // start the main function
{
	double lp0x, lp1x, lp0y, lp1y;
	double cmpx,cmpy;
	double radius;
        double distance;
        double diameter;
    
	srand(time(0));
    
	lp0x=(rand() % (999+999+1)-999) / 10.0;
	lp1x=(rand() % (999+999+1)-999) / 10.0;
	lp0y=(rand() % (999+999+1)-999) / 10.0;
	lp1y=(rand() % (999+999+1)-999) / 10.0;
    
	cmpx=(rand() % (999+999+1)-999) / 10.0;
	cmpy=(rand() % (999+999+1)-999) / 10.0;
    
	radius=(rand() % (999-1+1)+1) / 10.0;

    
	cout << "Line segment's 1st x coordinate: " << lp0x << endl;
	cout << "Line segment's 1st y coordinate: " << lp1x << endl;
	cout << "Line segment's 2nd x coordinate: " << lp0y << endl;
	cout << "Line segment's 2nd y coordinate: " << lp1y << endl;
	cout << "\n" << endl; // space
	cout << "Circle's Midpoint x coordinate: " << cmpx << endl;
	cout << "Circle's Midpoint y coordinate: " << cmpy << endl;
	cout << "Circle's Radius: " << radius << endl;
    
	distance = sqrt(pow(lp0x-lp1x,2.0) + pow(lp0y-lp1y,2.0));  
         
        cout << "\n" << endl; // space
    
	diameter = 2 * radius;
 
    
	if (distance<diameter)
		cout << "The line segment is in the circle!\n";
	else
		cout << "The line segment is not in the circle!\n";
    
    cout << "\n" << endl; // space
    
	return EXIT_SUCCESS;
    
}

Open in new window

Avatar of phoffric
phoffric

One thing that comes to mind with any program are (1) inputs, (2) processing, (3) outputs, and (4) displays or (5) menus. Each of these ideas can be a function. Your inputs are hard-coded, but you could change that to, say, provide a menu for the user to define a bounding square box where the random points go. Hope that helps.

(One interesting aside, is that if you count the total number of generated points, and count the number of random points that fit inside a circle that is inside a bounding square, then if you have a good random generator, you can approximate the value PI by comparing the area of the circle with the area of the square.).
Avatar of joedfuse

ASKER

Basically what im looking for is to take my code and re-write them using the 3 prototyped functions. Or more functions if thats required but I am thinking it will only take the 3. One for the random generation, one for the distance calculation and the third to check the distance against the diameter

Note: My code above works perfectly. Im not looking for a solution that just re builds my code for efficiency or anything. I just want to format it in sub functions with arguments.
Here are some pointers - rather than supply working code - if your aim is to learn C++ then it is better to do than to copy.

First question - what was your reasoning behind defining your prototypes with const reference pointers? You are not modifying any of the values you are passing through but just using them to return a value. There is no reason to define them either as const or as reference.

Secondly - you have the option to use functions or macros in this case. For example - generating your random numbers could be done with a Macro like so

#define RANDBL(min,max) min + (((double)rand() / RAND_MAX) * (max-min));

Open in new window


And called like so

lp0x=RANDBL(1,100);

Open in new window


In this case the result can be calculated in one statement - makes it ideally suited to a macro.  You can define it as a function as well

double randomDouble(double from, double to)
{
    return from + ( ( ( double ) rand() / RAND_MAX ) * ( to - from ) );
}
// Call like this
lp0x = randomDouble(1,100);

Open in new window

The Macro will be slightly more efficient than the function as the code required for pushing parameters to the stack and calling the function will be eliminated - in reality though the saving is almost negligable. So it comes down to preference.

With respect to converting the rest of the code to the functions you have defined - you can use a similar approach to the one shown above.

Give it a go and post back if you get stuck.
Thanks for your detailed response. It looks like your way seems to be a really good way to do it. The only problem is im only on chapter 3 in my book which is functions and sub functions.

I am having an issue understanding parameters and arguments in functions. I figured if someone can use some code I understand in a way I dont it would make more sense to me.

As for my thinking behind the const reference, I just took a shot based on what I read

If you want to show me a better way using functions that would work for me as well. Im not married to

Thanks again.
The previous post shows an example of how to call the randomDouble as a function instead of a Macro. Here is a short explanation of some stuff

Macro's - these are just compiler directives (instructions to the compiler) to basically do a search and replace at compile time. So in the case of the example above the compiler will replace the code

lp0x=RANDBL(1,100);

Open in new window


with

1 + (((double)rand() / RAND_MAX) * (100-1))

Open in new window


So you would end up pretty much with what you had in your original program.

The advantage of Macro's is it allows you to use shorthand (saves typing) and it makes your code look neater.

Functions and parameters

Functions - used primarily for two reasons

1. Reusable code - using the same functionality more than once
2. Structuring code - breaking code up into logical structures makes it easier to maintain.

Functions optionally take parameters to allow the same piece of code to do the same work but with different inputs (giving different answers). We pass parameters to the function and give those parameters names which are only visible inside the function - we can then manipulate the data how we wish using the parameter names.

C/C++ is one of those languages that requires you to do a bit more work than some other languages. When it comes to parameters there are basically two types

1. Input only (don't want the input values to change on exit)
2. Input / Output - you want to change the value of the incoming value so it stays changed when control returns to the calling code.

Here are two examples that help explain the concept.

int max(int a, int b)
{
    if (a < b) return b;
    return a;
}
...
int maxval = max(10,20);
cout << "Max : " << maxval << endl;
int a = 20;
int b = 50;
maxval = max(a, b);
cout << "Max : " << maxval << endl;

Open in new window

In this function we don't want to change the values passed to the function - all we want is an answer as to which is the max. As you will notice in this code we can either pass constant values or variable names

Take the example of a function to swap two values. Try it like this first

void swap(int a, int b)
{
    int temp;
    temp = a;
    a = b;
    b = temp;
}
int var1 = 10;
int var2 = 20;
swap(var1,var2);
// Output: a and b will NOT be swapped

Open in new window

In this example even though the swap code will in fact change the values of a and b around this will not affect the var1 and var2 values.
The reason for this is because the var1 and var2 values have been passed to the swap function by VALUE - which means the parameters a and b are created with their own memoray storage and copies of the values in var1 and var2 are put into a and b - so that the copies are swapped leaving the original values unchanged

To get around this we need to pass parameters to swap by REFERENCE which means instead of passing the value of var1 and var2 to the function we pass a pointer to the place where var1 and var2 store their values. In C this would be something like this
// The int * means a pointer to an int. It is telling the compiler that our function
// expects to receive a pointer to a memory location that stores an int - and not 
// the value of an int
void swap(int * a, int * b)
{
    int temp;
    // To access the value of the pointer we have to put a * in front to tell the compiler
    // don't use the value of this variable (which would be a memory address) but rather
    // use that value to lookup in memory where the value is stored and use that value
    temp = *a;

    *a = *b;
    *b = temp;
}
int var1 = 20;
int var2 = 30;
// To call it we would need to pass the address of the variables - not their value
// To do that we prefix the variable with the '&' like this
swap(&var1,&var2);

Open in new window

In the above example the address of var1 and var2 are passed to the swap function which in turn is modified to have the parameters treated as pointers to int's rather than int values.

In C++ you can define the reference parameter in the function declaration like so
void swap(int & a, int & b)
{
     int temp = a;
     a = b;
     b = temp;
}
int var1 = 20;
int var2 = 30;
swap(var1,var2);

Open in new window

In the above example we are passing the variables by refernce but we don't have to worry about pointer values.

By making the parameter declaration reference parameters int & a we are telling the compiler - this function is receiving a reference to a value and not the value itself. The compiler then does the heavy lifting of passing the address and de-referencing the variables in the function.

Note when passing values by reference you cannot use constant values. So swap(10,20) would not compile.

Hopefully the above makes sense and helps to bring some clarity
You say that you are having problems understanding some concepts in Chapter 3. Why not ask separate question(s) about those concepts and get a firm understanding of them before trying to tackle and exercise or assignment?
All im looking for is how to convert my code into 3 functions. I will figure it out from there.

Im sure there are other ways to do things but Im just looking to convert this code accordingly.

Thanks
Im sure there are other ways to do things but Im just looking to convert this code accordingly.

Open in new window

I think you will find - given you are in a learning situation - experts to write all the code for you.

My first post gives the basics of what you need. All you need to do is modify your prototypes of the other two functions to use the same declarative style as used for the randomDouble function.

Next copy the code for each of the functions (which in each case is just a single line) to the function and have it return the calculated value - as was done in randomDouble

And finally replace the code in the main body with calls to the functions with the parameters - basically take the variables you were using in the inline calculation.

If you can't get it to work - post what you have done and we can take it from there.
Now we are getting somewhere.... I think what you just wrote will help

I will let you know
Advise avoid using macro functions; try inline functions instead. Inline functions are safer to use and it avoids pushing parameters to another stack frame.
Yeah I wasn't going to mess with macros at this time. Again I'm just beginning so I am following a beginning book.
Ok so I spent some time playing with the suggestion. The following code has a bunch of errors toward the end of the code. I must be still missing something

#include <iostream>
#include <cstdlib>
#include <cmath>
#include <ctime>

using namespace std;

double randomDouble();
double lineSegLen(const double& lp0x, const double& lp0y, const double& lp1x, const double& lp1y);
bool lineInCircle(const double& lp0x, const double& lp0y, const double& lp1x, const double& lp1y, const double& cmpx, const double& cmpy, const double& radius);

int main ()
{
	double lp0x, lp1x, lp0y, lp1y;
	double cmpx,cmpy;
	double radius;
    double distance;
    double diameter;
    
	srand(time(0));
    
	lp0x= randomDouble();
	lp1x= randomDouble();
	lp0y= randomDouble();
	lp1y= randomDouble();
    
	cmpx= randomDouble();
	cmpy= randomDouble();
    
	radius= randomDouble();
    
    cout << "\n" << endl; // space
    
	cout << "Line segment's 1st x coordinate: " << lp0x << endl;
	cout << "Line segment's 1st y coordinate: " << lp1x << endl;
	cout << "Line segment's 2nd x coordinate: " << lp0y << endl;
	cout << "Line segment's 2nd y coordinate: " << lp1y << endl;
	cout << "\n" << endl; // space
	cout << "Circle's Midpoint x coordinate: " << cmpx << endl;
	cout << "Circle's Midpoint y coordinate: " << cmpy << endl;
	cout << "Circle's Radius: " << radius << endl;
    
	distance = lineSegLen(const double& lp0x, const double& lp0y, const double& lp1x, const double& lp1y);

    cout << "\n" << endl; // space
    
	lineInCircle(const double& lp0x, const double& lp0y, const double& lp1x, const double& lp1y, const double& cmpx, const double& cmpy, const double& radius);
    cout << "\n" << endl; // space
    
	return EXIT_SUCCESS;
    
}

double randomDouble()
{
    return = (rand() % (999+999+1)-999) / 10.0;
}

double lineSegLen(const double& lp0x, const double& lp0y, const double& lp1x, const double& lp1y)
{
    return = sqrt(pow(lp0x-lp1x,2.0) + pow(lp0y-lp1y,2.0));
}

bool lineInCircle(const double& lp0x, const double& lp0y, const double& lp1x, const double& lp1y, const double& cmpx, const double& cmpy, const double& radius, const double& diameter)
{
    
    diameter = 2 * radius;
    
	if (distance<diameter)
		return = cout << "The line segment is in the circle!\n";
	else
		return = cout << "The line segment is not in the circle!\n";

}

Open in new window

SOLUTION
Avatar of phoffric
phoffric

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Ok the modified code... its having a problem with the IF line

Im getting the error Type name requires a specifier or qualifier... Hopefully if I fix that this thing will fire

#include <iostream>
#include <cstdlib>
#include <cmath>
#include <ctime>

using namespace std;

double randomDouble();
double lineSegLen(const double& lp0x, const double& lp0y, const double& lp1x, const double& lp1y);
bool lineInCircle(const double& lp0x, const double& lp0y, const double& lp1x, const double& lp1y, const double& cmpx, const double& cmpy, const double& radius, const double& diameter);

int main ()
{
	double lp0x, lp1x, lp0y, lp1y;
	double cmpx,cmpy;
	double radius;
    double distance;
    double diameter;
    
	srand(time(0));
    
	lp0x= randomDouble();
	lp1x= randomDouble();
	lp0y= randomDouble();
	lp1y= randomDouble();
    
	cmpx= randomDouble();
	cmpy= randomDouble();
    
	radius= randomDouble();
    
    cout << " -----------" << endl;
    cout << "| Program 3 |" << endl;
    cout << " -----------" << endl;
    
    cout << "\n" << endl; // space
    
	cout << "Line segment's 1st x coordinate: " << lp0x << endl;
	cout << "Line segment's 1st y coordinate: " << lp1x << endl;
	cout << "Line segment's 2nd x coordinate: " << lp0y << endl;
	cout << "Line segment's 2nd y coordinate: " << lp1y << endl;
	cout << "\n" << endl; // space
	cout << "Circle's Midpoint x coordinate: " << cmpx << endl;
	cout << "Circle's Midpoint y coordinate: " << cmpy << endl;
	cout << "Circle's Radius: " << radius << endl;
    
	distance = lineSegLen(lp0x,lp0y,lp1x,lp1y);
    
    diameter = 2 * radius;


    cout << "\n" << endl; // space
    
	lineInCircle(lp0x,lp0y, lp1x, lp1y,cmpx, cmpy, radius, diameter);
    cout << "\n" << endl; // space
    
	return EXIT_SUCCESS;
    
}

double randomDouble()
{
    return (rand() % (999+999+1)-999) / 10.0;
}

double lineSegLen(const double& lp0x, const double& lp0y, const double& lp1x, const double& lp1y)
{
    return sqrt(pow(lp0x-lp1x,2.0) + pow(lp0y-lp1y,2.0));
}

bool lineInCircle(const double& lp0x, const double& lp0y, const double& lp1x, const double& lp1y, const double& cmpx, const double& cmpy, const double& radius, const double& diameter)
{
    
    
	if (distance<diameter)
		cout << "The line segment is in the circle!\n";
	else
		cout << "The line segment is not in the circle!\n";

}

Open in new window

Remove using namespace std; and adjust like: std::cout, etc.

Change variable or argument names slightly from other identical names from function to function. That should help.

I see that in lineInCircle, you added diameter, but you didn't define distance.
ASKER CERTIFIED SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Ok so I made some tweaks to both your suggestions and finally got it to work. Also, I have a much better understanding about using sub functions

#include <iostream>
#include <cstdlib>
#include <cmath>
#include <ctime>

using namespace std;

double randomDouble();
double lineSegLen(const double& lp0x, const double& lp0y, const double& lp1x, const double& lp1y);
bool lineInCircle(const double& lp0x, const double& lp0y, const double& lp1x, const double& lp1y, const double& cmpx, const double& cmpy, const double& radius, const double& diameter, const double& distance);

int main ()
{
	double lp0x, lp1x, lp0y, lp1y;
	double cmpx,cmpy;
	double radius;
    double distance;
    double diameter;
    
	srand(time(0));
    
	lp0x= randomDouble();
	lp1x= randomDouble();
	lp0y= randomDouble();
	lp1y= randomDouble();
    
	cmpx= randomDouble();
	cmpy= randomDouble();
    
	radius= randomDouble();
    
    cout << "\n" << endl; // space
    
	cout << "Line segment's 1st x coordinate: " << lp0x << endl;
	cout << "Line segment's 1st y coordinate: " << lp1x << endl;
	cout << "Line segment's 2nd x coordinate: " << lp0y << endl;
	cout << "Line segment's 2nd y coordinate: " << lp1y << endl;
	cout << "\n" << endl; // space
	cout << "Circle's Midpoint x coordinate: " << cmpx << endl;
	cout << "Circle's Midpoint y coordinate: " << cmpy << endl;
	cout << "Circle's Radius: " << radius << endl;
    
	distance = lineSegLen(lp0x,lp0y,lp1x,lp1y);
    
    diameter = 2 * radius;


    cout << "\n" << endl; // space
    
	lineInCircle(lp0x,lp0y,lp1x,lp1y,cmpx,cmpy,radius,diameter,distance);
    
    if (lineInCircle(lp0x,lp0y,lp1x,lp1y,cmpx,cmpy,radius,diameter,distance))
        cout << "The line segment is in the circle!\n";
    else
        cout << "The line segment is not in the circle!\n";
    
    
    cout << "\n" << endl; // space
    
	return EXIT_SUCCESS;
    
}

double randomDouble()
{
    return (rand() % (999+999+1)-999) / 10.0;
}

double lineSegLen(const double& lp0x, const double& lp0y, const double& lp1x, const double& lp1y)
{
    return sqrt(pow(lp0x-lp1x,2.0) + pow(lp0y-lp1y,2.0));
}

bool lineInCircle(const double& lp0x, const double& lp0y, const double& lp1x, const double& lp1y, const double& cmpx, const double& cmpy, const double& radius, const double& diameter, const double& distance)
{
    
    return  (distance<diameter);
    
}

Open in new window