static vector much slower than global in recursive function - c++

I want to use static variables instead of global variables, found it was much slower than before. The original code took less than 0.01 seconds, now it takes about 1.6 seconds.
I am not familiar with vector. Is there a simple way to get the same performance as before?
#include <cstdio>
#include <cmath>
#include <ctime>
#include <vector>
using namespace std;
vector<double> fun(double x1, double y1, double x5, double y5, int i)
{
static vector<double> vec;
double x2 = (2 * x1 + x5) / 3;
double y2 = (2 * y1 + y5) / 3;
double x3 = (x1 + x5) / 2. + (y1 - y5) / (2. * sqrt(3));
double y3 = (-x1 + x5) / (2. * sqrt(3)) + (y1 + y5) / 2.;
double x4 = (x1 + 2 * x5) / 3;
double y4 = (y1 + 2 * y5) / 3.;
if (i <= 1)
{
vec.push_back(x1);
vec.push_back(y1);
vec.push_back(x2);
vec.push_back(y2);
vec.push_back(x3);
vec.push_back(y3);
vec.push_back(x4);
vec.push_back(y4);
vec.push_back(x5);
vec.push_back(y5);
}
else
{
fun(x1, y1, x2, y2, i - 1);
fun(x2, y2, x3, y3, i - 1);
fun(x3, y3, x4, y4, i - 1);
fun(x4, y4, x5, y5, i - 1);
}
return vec;
}
int main(int argC, char** argV)
{
clock_t t0 = clock();
int n = 8;
vector<double> vec = fun(0, 0, 1, 0, n);
printf("%d\n", vec.size());
printf("time %0.4fs\n", (clock() - t0) / 1000.0);
return 0;
}

There are two factors,
The minor factor is that every time the function enters, the program checks whether the variable has been initialized (and this must be thread safe)
The major factor is that you're returning a copy of the vector from every call, even though you ignore almost all of them. (There are 21,845 vector copies, each involving a memory allocation and deallocation, with a total of 1,790,197,760 doubles being copied. That's almost 15 gigabytes.)
The simple way to solve both the performance issue and the issue of only being able to solve the problem once is to accumulate the result in a reference argument:
void fun(double x1, double y1, double x5, double y5, int i, vector<double>& vec)
and remove the local vec from fun, and then in main,
vector<double> vec;
fun(0, 0, 1, 0, n, vec);
No other changes should be necessary.

Related

how to pass multiple variables from main function down to other functions C++

I am stuck on this program as follows:
Write a program that takes as input five numbers and outputs the mean (average) and standard deviation of the numbers. If the numbers are x1,x2,x3,x4,x5.
To solve mean : mean = (x1 + x2 + x3 + x4 + x5) / 5;
To solve deviation:
deviation = sqrt((pow(x1 - x, 2) + pow(x2 - x, 2) + pow(x3 - x, 2) + pow(x4 - x, 2) + pow(x5 - x, 2)) / 5);
Your program must contain at least the following functions: a function that calculates and returns the mean and a function that calculates the standard deviation.
I am trying to use variable x1,x2,x3,x4,x5 from main but I am getting unitialized local variable errors and can not compile it.
#include <iostream>
#include <cmath>
using namespace std;
// Named constant definitions (and function declarations):
//Prototype
double meanfn();
double deviationfn();
// Main program:
int main()
{
// Variable declarations:
double x1, x2, x3, x4, x5;
// Function body:
cout << "Enter a number followed by space 5 times to calculate the mean of five numbers. " << endl;
cin >> x1 >> x2 >> x3 >> x4 >> x5;
return 0;
} // end function main
double meanfn()
{
double x1, x2, x3, x4, x5;
double mean;
mean = (x1 + x2 + x3 + x4 + x5) / 5;
return mean;
}// end function meanfn
double deviationfn(double mean)
{
double x,deviation;
double x1, x2, x3, x4, x5;
x = mean;
deviation = sqrt((pow(x1 - x, 2) + pow(x2 - x, 2) + pow(x3 - x, 2) + pow(x4 - x, 2) + pow(x5 - x, 2)) / 5);
return deviation;
}
You have two problems of understanding basics in C++:
Variable scope.
Function parameters.
To briefly explain:
Variables in C++ live only in the scope they were declared in. In your case, you declared: x1, x2, x3, x4, x5 inside of the function main which means they do not exist outside that scope. The variables x1, x2, x3, x4, x5 in meanfn and deviationfn are completely different variables. They only share the same names and that's about it. Therefore, when you declared them inside the functions, they had no previously assigned values which means you cannot use them.
As for function parameters, you have to declare what parameters a function accepts in its signature. Your meanfn signature is double meanfn() which accepts no parameters. If you want it to accept 5 and only 5 double variables, you should change it to accommodate.
There are two solutions based on the explanations above:
#include <iostream>
#include <cmath>
using namespace std;
// Named constant definitions (and function declarations):
//Prototype
double meanfn();
double deviationfn();
// Main program:
// Variable declarations:
double x1, x2, x3, x4, x5; // outside of 'main' making them global and everything has access to these variables.
int main()
{
// Function body:
cout << "Enter a number followed by space 5 times to calculate the mean of five numbers. " << endl;
cin >> x1 >> x2 >> x3 >> x4 >> x5;
// CALL YOUR FUNCTIONS, THEY WONT BE CALLED BY THEIR OWN
double mean = meanfn();
double deviation = deviationfn(mean);
// print results
std::cout << "\n Mean: " << mean << "\n Deviation: " << deviation;
return 0;
} // end function main
double meanfn()
{
double mean = (x1 + x2 + x3 + x4 + x5) / 5;
return mean;
}// end function meanfn
double deviationfn(double mean)
{
double x,deviation;
x = mean;
deviation = sqrt((pow(x1 - x, 2) + pow(x2 - x, 2) + pow(x3 - x, 2) + pow(x4 - x, 2) + pow(x5 - x, 2)) / 5);
return deviation;
}
In the solution above, the variables x1, x2, x3, x4, x5 were moved to be global variables making their access global and hence all functions can use them.
The second solution would consider parameter passing for the functions, such as:
#include <iostream>
#include <cmath>
using namespace std;
// Named constant definitions (and function declarations):
//Prototype
double meanfn(double x1, double x2, double x3, double x4, double x5);
double deviationfn(double mean, double x1, double x2, double x3, double x4, double x5);
// Main program:
int main()
{
// Variable declarations:
double x1, x2, x3, x4, x5;
// Function body:
cout << "Enter a number followed by space 5 times to calculate the mean of five numbers. " << endl;
cin >> x1 >> x2 >> x3 >> x4 >> x5;
// see the difference in the function calls?
double mean = meanfn(x1, x2, x3, x4, x5);
double deviation = deviationfn(mean, x1, x2, x3, x4, x5);
// print results
std::cout << "\n Mean: " << mean << "\n Deviation: " << deviation;
return 0;
} // end function main
double meanfn(double x1, double x2, double x3, double x4, double x5)
{
double mean;
mean = (x1 + x2 + x3 + x4 + x5) / 5;
return mean;
}// end function meanfn
double deviationfn(double mean, double x1, double x2, double x3, double x4, double x5)
{
double x,deviation;
x = mean;
deviation = sqrt((pow(x1 - x, 2) + pow(x2 - x, 2) + pow(x3 - x, 2) + pow(x4 - x, 2) + pow(x5 - x, 2)) / 5);
return deviation;
}
Rather than having 5 variables with numbered names, you can instead have one variable that contains all 5.
#include <iostream>
#include <cmath>
#include <array>
using Values = std::array<double, 5>;
double mean(Values xs)
{
return (xs[0] + xs[1] + xs[2] + xs[3] + xs[4]) / xs.size();
}
double distribution(Values xs, double x_bar)
{
return sqrt((pow(xs[0] - x_bar, 2) + pow(xs[1] - x_bar, 2) + pow(xs[2] - x_bar, 2) + pow(xs[3] - x_bar, 2) + pow(xs[4] - x_bar, 2)) / xs.size());
}
int main()
{
std::cout << "Enter a number followed by space 5 times to calculate the mean of five numbers. " << std::endl;
Values xs;
std::cin >> xs[0] >> xs[1] >> xs[2] >> xs[3] >> xs[4];
auto x_bar = mean(xs);
auto sigma = distribution(xs, x_bar);
std::cout << "\n Mean: " << x_bar << "\n Deviation: " << sigma;
}
But notice that each of those functions is doing the same operation to each of the values, then performing some final calculation based on how many. That can better be expressed using functions from <algorithm>. We then don't need to know how many elements there are.
#include <algorithm>
#include <vector>
using Values = std::vector<double>; // Any number of values
double mean(Values xs)
{
// The default combiner is +
return std::accumulate(xs.begin(), xs.end(), 0) / xs.size();
}
double distribution(Values xs, double x_bar)
{
auto sum_squares = [x_bar](double cumulative, double x){ return cumulative + pow(x - x_bar, 2); }
return sqrt(std::accumulate(xs.begin(), xs.end(), 0, sum_squares) / xs.size());
}

elegant template overloading solution?

In c++11 I have functions
double f(double x1);
double f(double x1, double x2);
double f(double x1, double x2, double x3);
double h(double x);
I also have functions
double g(std::vector<double> y, double x1);
double g(std::vector<double> y, double x1, double x2);
double g(std::vector<double> y, double x1, double x2, double x3);
The implementation of g is something like
double g(std::vector<double> y, double x1, double x2, double x3)
{
double ans = 0.0;
for(g : y)
{
ans = h(g) * f(x1, x2, x3);
}
return ans;
}
Is there an elegant (templated) way of doing this instead of writing g 3 times with overloaded arguments?
template<typename... Ts>
double g(std::vector<double> v, Ts&&...ts ) {
double ret = 1;
for(auto x:v){
ret *= h(x)*f(ts...);
}
return ret;
}
if you want to restrict the ts to be doubles beyond calling f, it needs more work. Otherwise, the above is enough.
(Note the resriction work gets prettier in C++1y with concepts lite: in C++11 I vote to skip the restriction of Ts to doubles, and just rely on f only taking doubles.)

Finding minimum and maximum points coordinates with C++

I have a text file that include X,Y,Z coordinates of points. My aim is finding minimum and maximum points and write it another file. For this aim I write a distance function. The points that have maximum distance is minimum and maximum points. here is my code. It works but it does not calculate or write anything.
#include <iostream>
#include<fstream>
#include <math.h>
using namespace std;
double distance (float X1, float Y1, float Z1, float X2, float Y2, float Z2)
{
return sqrt(pow((X2-X1),2)+ pow((Y2-Y1),2)+pow((Z2-Z1),2));
}
int main ()
{
float x1, y1, z1,x2, y2,z2;
ifstream file("D:\\points.txt");
ofstream result ("D:\\result.txt");
double bigdistance=0;
if (file.is_open())
{
while (!file.eof())
{
file>>x1>>y1>>z1;
while (!file.eof())
{
file>>x2>>y2>>z2;
double d= distance (x1,y1,z1,x2,y2,z2);
if (bigdistance<d)
{
bigdistance=d;
result<<x1<<y1<<z1<<endl<<x2<<y2<<z2;
}
}
}
}
else cout <<"cannot open file";
system ("PAUSE");
return 0;
}
A couple of suggestions:
while (file >> x1 >> y1 >> z1 >> x2 >> y2 >> z2) {
}
will read your input and stop if any of the reads failed.
You will want to read the entire input and store it in a vector of points, or similar. Then, you can use two nested loops to iterate over each pair of points. Right now, your programs assumes that the input file contains all pairs. That is, each point is read multiple times form the input, in the inner loop.
There are also algorithms that are faster than quadratic, and you might need those if you have more than a couple thousand input points. See for example this StackOverflow question.
#include <iostream>
#include<fstream>
#include <math.h>
using namespace std;
enter code here`{
for (int i = 1; !f1.eof(); i++)
{
int x1, y1, x2, y2, x3, y3, x4, y4);
read(f1, x1, y1, x3, y3);
x2 = x3;
y2 = y1;
x4 = x1;
y4 = y3;
if (y4 > y1)
{
a = y1 - y4;
}
else
a = y4 - y1;
if (x4 > x3)
{
b = x4 - x3;
}
else
b = x3 - x4;
}
}

Polygon intersection with Boost::geometry severe performance deterioration

I have a particle system and I am using boost::geometry to approximate my elliptical particles as polygons and then use the intersection function of the library to find the overlap area. I am calculating an "inner" and "outer" ellipse(polygon) area to assign a "potential" for each particle-particle interaction.
My potential function is this:
double Potential(Cell* current, Cell* next)
{
double areaRep, areaAtt;
double distance = Distance(current,next);
double A1 = current->getLength();
double B1 = A1/2.0;
double theta1 = current->getTheta(); //*180.0/M_PI
double x1 = current->getCurrX();
double y1 = current->getCurrY();
double A2 = next->getLength();
double B2 = A2/2.0;
double theta2 = next->getTheta();
double x2 = next->getCurrX();
double y2 = next->getCurrY();
polygon_2d poly1, poly2, poly3, poly4;
double lamda1, lamda2;
lamda1 = 0.0005; lamda2 = 0.00001;
if(distance < 2.0*1.5*A1) {
ellipse2poly(theta1, A1, B1, x1, y1, &poly1);
ellipse2poly(theta2, A2, B2, x2, y2, &poly2);
areaRep = getOverlapingAreaPoly(poly1,poly2);
ellipse2poly(theta1, 1.5*A1, 1.5*B1, x1, y1, &poly3);
ellipse2poly(theta2, 1.5*A2, 1.5*B2, x2, y2, &poly4);
areaAtt = getOverlapingAreaPoly(poly3, poly4);
return (lamda1*areaRep - lamda2*areaAtt);
}
else
return 0.0;
}
The "polygonizing" function is:
int ellipse2poly(double theta, double A1, double B1, double H1, double K1, polygon_2d *po)
{
using namespace boost::geometry;
polygon_2d poly;
const int n = 20;
double angle = theta; // cell orientation
double a = A1; // Long semi-axis length
double b = B1; // short semi-axis length
double xc = H1; // current X position
double yc = K1; // current Y position
if(!n)
{
std::cout << "error ellipse(): n should be >0\n" <<std::endl;
return 0;
}
double t = 0;
int i = 0;
double coor[2*n+1][2];
double x, y;
double step = M_PI/(double)n;
double sinphi = sin(angle);
double cosphi = cos(angle);
for(i=0; i<2*n+1; i++)
{
x = xc + a*cos(t)*cosphi - b*sin(t)*sinphi;
y = yc + a*cos(t)*sinphi + b*sin(t)*cosphi;
coor[i][0] = x;
coor[i][1] = y;
t += step;
}
assign_points(poly, coor);
correct(poly);
*po = poly;
return 1;
}
And the returned area is:
double getOverlapingAreaPoly(polygon_2d poly, polygon_2d poly2)
{
point_2d cent; //centre of overlaping area
double overAreaPoly = 0.0;
typedef std::vector<polygon_2d > polygon_list;
polygon_list v;
intersection(poly,poly2,v);
for (polygon_list::const_iterator it = v.begin(); it != v.end(); ++it)
{
centroid(*it, cent);
overAreaPoly = area(*it);
}
return overAreaPoly;
}
The function is called for every cell (particle) as long as it is not for the same one. Previously, using another method, one iteration of my algorithm would take approximately 43 ms for one iteration for 100 particles. Now it takes approximately 1 min(!!!), so I guess I have done something horribly wrong!
I have tested this only in MSVC2012 under win7 64bit. I will report back for Linux Mint with Qt 4.7.4.
EDIT:
I have tested on Linux Mint with Qt 4.7.4 and it is running very reasonably; maybe 90-100 ms per iteration which is fine. I don't know what is wrong in win7...
I have actually fixed it. I started a new project in Visual Studio and copied all source and header files, recompiled and everything runs smoothly now. I guess radically changing code and adding / subtracting stuff must have some impact...

Unknown bug affecting Graham's algorithm for finding convex hull

I have programmed the Graham's algorithm but it still gives me the wrong points for the convex hull. I need help. Think I have a bug in my sign function but dunno what it is.
#include <cstdio>
#include <algorithm>
#include <math.h>
#define pb push_back
#define mp make_pair
#include <vector>
using namespace std;
vector <pair<double, double> > st;
pair<double, double> p[1000];
double x, y;
int f(pair <double,double> a, pair<double, double> b)
{
double x1 = x - a.first, x2 = x - b.first;
double y1 = y - a.second, y2 = y - b.second;
return ((x1*y2-y1*x2) < 0);
}
void setlast(double &x1, double &y1, double &x2, double &y2)
{
x2 = st[st.size()-1].first;
y2 = st[st.size()-1].second;
x1 = st[st.size()-2].first;
y1 = st[st.size()-2].second;
}
sign improved I use doubles
double sign(double x1,double y1, double x2,double y2, double y3,double x3)
{
double xx1 = x2 - x1, xx2 = x3 - x1;
double yy1 = y2 - y1, yy2 = y3 - y1;
return (xx1*yy2-yy1*xx2);
}
int main()
{
int n;
x = 0x3f3f3f3f;
y = 0x3f3f3f3f;
scanf("%d", &n);
for(int i = 0; i < n; i++)
{
scanf("%lf %lf", &p[i].first, &p[i].second);
if(p[i].first <= x && p[i].second <= y)
x = p[i].first,
y = p[i].second;
}
sort(p, p + n, f);
p[n].first = x;
p[n].second = y;
st.pb(mp(p[0].first, p[0].second));
st.pb(mp(p[1].first, p[1].second));
double x1, x2, x3, y1, y2, y3;
here I iterate through all vectors and try to determine the points of convex hull
for(int i = 2; i < n; i++)
{
x3 = p[i].first;
y3 = p[i].second;
setlast(x1,y1,x2,y2);
while(1)
if(sign(x1,y1,x2,y2,x3,y3) < 0)
{
st.pb(mp(x3, y3));
break;
}
else
st.pop_back(),
setlast(x1, y1, x2, y2);
}
here printing the convex hull
for(int i = 0; i < st.size(); i++)
printf("%lf %lf\n", st[i].first, st[i].second);
return 0
}
My question, why does int f(pair<int, int>, pair<int, int>) take pair<int, int> instead of pair<double, double>?
Also, why isn't it named something informative like compare_blah?
Lastly, why doesn't it return bool instead of an int? Either works of course, but it will be clearer that this is intended simply as a comparison function if you return a bool. And making your program clear to people who read it should be your primary goal. Getting it to do what it's supposed to is a secondary goal. After all, it doing what it's supposed to is only a transitory state of affairs. Eventually someone will want it to do something else.
The pair<int, int> thing could be your problem right there. You are doing several implicit type conversions in that function between int and double and losing information left and right. I doubt that's what you intended.
If you would use a typedef for your pair like typedef pair<double, double> point2d_t and then use point2d_t everywhere you could protect yourself from mistakes like that and make your program clearer in the bargain.
I'm not familiar enough with Graham's algorithm to evaluate your use of abs inside of f, though it's quite possible the person who commented on this is correct.