I just started taking this C++ course like a month ago.
Now I'm assigned to write a program to calculate this. I don't know what I did wrong.
#include <stdio.h>
#include <math.h>
float gatherl1();
float gatherl2();
float gatheran();
void values(float,float,float);
float findlength(float,float,float);
float findan2(float,float,float);
float findan3(float,float,float);
void name(float,float,float);
int main(void)
{
float length1,length2;
float length3;
float angle1,angle2,angle3;
length1 = gatherl1();
length2 = gatherl2();
angle1 = gatheran();
values(length1,length2,angle1);
length3 = findlength(length1,length2,angle1);
angle2 = findan2(length1,length2,length3);
angle3 = findan3(length1,length2,length3);
name(angle1,angle2,angle3);
}
float gatherl1()
{
float l1;
printf("Enter the length of one of the sides of any triangle\n");
scanf("%f",&l1);
return l1;
}
float gatherl2()
{
float l2;
printf("Enter the length of the other side\n");
scanf("%f",&l2);
return l2;
}
float gatheran()
{
float angle;
printf("Enter the angle between them.\n");
scanf("%f",&angle);
return angle;
}
void values(float l1, float l2, float angle)
{
printf("\n The two sides are %f and %f. The angle between them is %f \n",l1,l2,angle);
}
float findlength(float l1, float l2, float angle)
{
float l3,pyt,boy;
if (angle==90)
{
pyt = pow(l1,2) + pow(l2,2);
l3 = sqrt(pyt);
}
else
{
boy = pow(l1,2) + pow(l2,2) - 2*l1*l2*cos(angle);
l3 = sqrt(boy);
}
printf("\nthe third side is = %f",l3);
return l3;
}
float findan2(float l1, float l2, float l3)
{
float cosangle2,angle2;
cosangle2 = (pow(l2,2) + pow(l3,2) - pow(l1,2)) / (2*l2*l3);
angle2 = acos(cosangle2);
return angle2;
}
float findan3(float l1, float l2, float l3)
{
float cosangle3,angle3;
cosangle3 = (pow(l1,2) + pow(l3,2) - pow(l2,2)) / (2*l1*l3);
angle3 = acos(cosangle3);
return angle3;
}
void name(angle,angle2,angle3)
{
printf("\n\n\n the other two angles are %f and %f",angle2,angle3);
printf("\n\n\n The angle you put is %f",angle);
if(angle == 90)
{
printf("\n The triangle is a right triangle\n");
}
else if(angle < 90)
{
printf("\n The triangle is a acute triangle\n");
}
else
{
printf("\n The triangle is a obtuse triangle\n");
}
}
I have never use cos and arccos function before so I'm not sure if that's the cause.
or the function because I'm new to function too. Please Help Me!! thank you.
Are the values that you pass to your functions in terms of radians? Because cos and arccos assume radians as an input.
The C trigonometry functions operate in radians, not degrees. You have to multiply by pi/180 to convert degrees to radians.
Related
I am trying to solve differential heat equation using Thomas algorithm.
Physical problem: We have plug, left side is having temperature 0, right side temperature is 1.
For Thomas algorithm I have written a function, which accept three QVector and int value amount of equations.
This is my code:
#include <QCoreApplication>
#include <QVector>
#include <QDebug>
#include <iostream>
using std::cin;
void enterIn(QVector<float> &Array, int Amount_of_elements){
int transit;
for(int i=0;i<Amount_of_elements;i++){
cin>>transit;
Array.push_back(transit);
}
}
QVector<float> shuttle_method(const QVector<float> &below_main_diagonal,
QVector<float> &main_diagonal,
const QVector<float> &beyond_main_diagonal,
const QVector<float> &free_term,
const int N){
QVector <float> c;
QVector <float> d;
for(int i=0;i<N;i++){
main_diagonal[i]*=(-1);
}
QVector<float> x; //result
c.push_back(beyond_main_diagonal[0]/main_diagonal[0]);
d.push_back(-free_term[0]/main_diagonal[0]);
for(int i=1;i<=N-2;i++){
c.push_back(beyond_main_diagonal[i]/(main_diagonal[i]-below_main_diagonal[i]*c[i-1]));
d.push_back( (below_main_diagonal[i]*d[i-1] - free_term[i]) / (main_diagonal[i]- below_main_diagonal[i]*c[i-1]) );
}
x.resize(N);
//qDebug()<<x.size()<<endl;
int n=N-1;
x[n]=(below_main_diagonal[n]*d[n-1]-free_term[n])/(main_diagonal[n]-below_main_diagonal[n]*c[n-1]);
for(int i=n-1;i>=0;i--){
x[i]=c[i]*x[i+1]+d[i];
// qDebug()<<x[i]<<endl;
}
return x;
}
int main()
{
QVector <float> alpha; // below
QVector <float> beta; // main diagonal * (-1)
QVector <float> gamma; // beyond
QVector <float> b; // free term
QVector<float> T;
int cells_x=40; //amount of equations
alpha.resize(cells_x);
beta.resize(cells_x);
gamma.resize(cells_x);
b.resize(cells_x);
T.resize(cells_x);
float dt=0.2,h=0.1;
alpha[0]=0;
for(int i=1;i<cells_x;i++){
alpha[i]= -dt/(h*h);
}
for(int i=0;i<cells_x;i++){
beta[i] = (2*dt)/(h*h)+1;
}
for(int i=0;i<cells_x-1;i++){
gamma[i]= -dt/(h*h);
}
gamma[cells_x-1]=0;
qDebug()<<"alpha= "<<endl<<alpha.size()<<alpha<<endl<<"beta = "<<endl<<beta.size()<<beta<<endl<<"gamma= "<<gamma.size()<<gamma<<endl;
for(int i=0;i<cells_x-1;i++){
T[i]=0;
}
T[cells_x-1]=1;
qDebug()<<endl<<endl<<T<<endl;
//qDebug()<< shuttle_method(alpha,beta,gamma,b,N);
QVector<float> Tn;
Tn.resize(cells_x);
Tn = shuttle_method(alpha,beta,gamma,T,cells_x);
Tn[0]=0;Tn[cells_x-1]=1;
for(int stepTime = 0; stepTime < 50; stepTime++){
Tn = shuttle_method(alpha,beta,gamma,Tn,cells_x);
Tn[0]=0;
Tn[cells_x-1]=1;
qDebug()<<Tn<<endl;
}
return 0;
}
My problem is:
when I compile and run it I am getting this:
Tn <20 items> QVector<float>
0 float
0.000425464 float
0.000664658 float
0.000937085 float
0.00125637 float
0.00163846 float
0.00210249 float
0.00267163 float
0.00337436 float
0.00424581 float
0.00532955 float
0.00667976 float
0.00836396 float
0.0104664 float
0.0130921 float
0.0163724 float
0.0204714 float
0.0255939 float
0.0319961 float
Tn <20 items> QVector<float>
0 float
-0.000425464 float
0.000643385 float
-0.000926707 float
0.00120951 float
-0.00161561 float
0.00202056 float
-0.00263167 float
0.00324078 float
-0.00418065 float
0.00511726 float
-0.00657621 float
0.00802998 float
-0.0103034 float
0.0125688 float
-0.0161171 float
0.0196527 float
-0.0251945 float
0.0307164 float
1 float
Tn <20 items> QVector<float>
0 float
0.000425464 float
0.000664658 float
0.000937085 float
0.00125637 float
0.00163846 float
0.00210249 float
0.00267163 float
0.00337436 float
0.00424581 float
0.00532955 float
0.00667976 float
0.00836396 float
0.0104664 float
0.0130921 float
0.0163724 float
0.0204714 float
0.0255939 float
0.0319961 float
Tn <20 items> QVector<float>
0 float
-0.000425464 float
0.000643385 float
-0.000926707 float
0.00120951 float
-0.00161561 float
0.00202056 float
-0.00263167 float
0.00324078 float
-0.00418065 float
0.00511726 float
-0.00657621 float
0.00802998 float
-0.0103034 float
0.0125688 float
-0.0161171 float
0.0196527 float
-0.0251945 float
0.0307164 float
1 float
Again and again in loop.
I have no idea why I am getting this.
Maybe my mistake is in assign Tn result of my Thomas-method-function?
or in realization of Thomas method? or in boundary conditions?
I got it!
Boundary conditions must be acting to vectors
QVector<float> below_main_diagonal,
QVector<float> main_diagonal,
QVector<float> beyond_main_diagonal
so that T[0] must be 0 and T[N-1] must be 1. We can do it this way:
main_diagonal.first()=1;
main_diagonal.last()=1;
beyond_main_diagonal.first()=0;
below_main_diagonal.last()=0;
and due to this T[0] will be always equal to zero and T[N-1] will be equal to 1;
And in the article where I read about Thomas method the first step was to negate main diagonal, I have done it, but then in the end of the function I must do reverse thing, so:
for(int i(0);i<N;++i){
main_diagonal[i]*=(-1);
}
and we can use this function again, this is not absolutely optimal, but it is working stable.
Then, the whole code will be look like this:
#include <QCoreApplication>
#include <QVector>
#include <QDebug>
#include <iostream>
QVector<float> Thomas_Algorithm( QVector<float> &below_main_diagonal ,
QVector<float> &main_diagonal ,
QVector<float> &beyond_main_diagonal ,
QVector<float> &free_term,
const int N){
QVector<float> x; //vector of result
// checking of input data
if(below_main_diagonal.size()!=main_diagonal.size()||
main_diagonal.size()!=beyond_main_diagonal.size()||
free_term.size()!=main_diagonal.size())
{ qDebug()<<"Error!\n"
"Error with accepting Arrays! Dimensities are different!"<<endl;
x.resize(0);
return x;
}
if(below_main_diagonal[0]!=0){
qDebug()<< "Error!\n"
"First element of below_main_diagonal must be equal to zero!"<<endl;
x.resize(0);
return x;
}
if(beyond_main_diagonal.last()!=0){
qDebug()<< "Error!\n"
"Last element of beyond_main_diagonal must be equal to zero!"<<endl;
x.resize(0);
return x;
}
// end of checking
QVector <float> c;
QVector <float> d;
for(int i=0;i<N;i++){
main_diagonal[i]*=(-1);
}
c.push_back(beyond_main_diagonal[0]/main_diagonal[0]);
d.push_back(-free_term[0]/main_diagonal[0]);
for(int i=1;i<=N-2;i++){
c.push_back(beyond_main_diagonal[i]/(main_diagonal[i]-below_main_diagonal[i]*c[i-1]));
d.push_back( (below_main_diagonal[i]*d[i-1] - free_term[i]) /
(main_diagonal[i]- below_main_diagonal[i]*c[i-1]) );
}
x.resize(N);
int n=N-1;
x[n]=(below_main_diagonal[n]*d[n-1]-free_term[n])/(main_diagonal[n]-below_main_diagonal[n]*c[n-1]);
for(int i=n-1;i>=0;i--){
x[i]=c[i]*x[i+1]+d[i];
}
for(int i(0);i<N;++i){
main_diagonal[i]*=(-1);
}
return x;
}
int main()
{
QVector <float> alpha; // below
QVector <float> beta; // main diagonal * (-1)
QVector <float> gamma; // beyond
QVector <float> b; // free term
QVector<float> T;
int cells_x=30; // amount of steps
alpha.resize(cells_x);
beta.resize(cells_x);
gamma.resize(cells_x);
T.resize(cells_x );
float dt=0.2,h=0.1;
alpha[0]=0;
for(int i=1;i<cells_x-1;i++){
alpha[i]= -dt/(h*h);
}
alpha[cells_x-1]=0;
beta[0]=1;
for(int i=1;i<cells_x-1;i++){
beta[i] = (2*dt)/(h*h)+1;
}
beta[cells_x-1]=1;
gamma[0]=0;
for(int i=1;i<cells_x-1;i++){
gamma[i]= -dt/(h*h);
}
gamma[cells_x-1]=0;
for(int i=0;i<cells_x-1;i++){
T[i]=0;
}
T[cells_x-1]=1;
QVector<float>Tn;
Tn.resize(cells_x);
Tn= Thomas_Algorithm(alpha,beta,gamma,T,cells_x);
// boundary conditions!
beta.first()=1;
beta.last()=1;
gamma.first()=0;
alpha.last()=0;
// and then due to bc we always have T[0]=0 and T[n]=1
for(int stepTime=0;stepTime<100;stepTime++){
Tn = Thomas_Algorithm(alpha,beta,gamma,Tn,cells_x);
qDebug()<<"stepTime = "<<stepTime<<endl<<endl;
qDebug()<<Tn<<endl;
// boundary conditions!
beta.first()=1;
beta.last()=1;
gamma.first()=0;
alpha.last()=0;
// and then due to bc we always have T[0]=0 and T[n]=1
}
return 0;
}
and in the last step we are going to get absolutely "physical" results:
Tn <30 items> QVector<float>
0 float
0.0344828 float
0.0689656 float
0.103448 float
0.137931 float
0.172414 float
0.206897 float
0.24138 float
0.275862 float
0.310345 float
0.344828 float
0.379311 float
0.413793 float
0.448276 float
0.482759 float
0.517242 float
0.551724 float
0.586207 float
0.62069 float
0.655173 float
0.689655 float
0.724138 float
0.758621 float
0.793104 float
0.827586 float
0.862069 float
0.896552 float
0.931035 float
0.965517 float
1 float
I want to build a program that stimulate the behavior of a projectile motion. I have checked the coordinates (x, y) which are correct but the compiler is not printing at right coordinates resulting in an inverted projectile motion(swing like motion)
the file "myconsole.h"is working correctly I have checked it separately.
here is my code:
#include <iostream>
#include <cmath>
#include <windows.h>
#include "myconsole.h"
using namespace std;
int coordinate(int theta, float v, float g, float initialheight, float x) //function to calculate y coordinate. it accepts x and produces y
{
float y = ((initialheight + (x * tan(theta))) - (( g * (x * x))/(2 * (powf((v * cos(theta)), 2)))));//formula
return y;
}
int main()
{
float initialheight = 0;
int y = 0;
int x = 0;
float v = 0;
int theta =0;
float g = 9.81;
cout<<"Enter the following Information"<<endl;
cout<<"Angle (theta) = ";
cin>>theta;
cout<<"Initial Velocity (V) = ";
cin>>v;
cout<<"Initial height = ";
cin>>initialheight;
float sq = 2*g*initialheight;//just for simplification
float sqroot = powf(v * (sin(theta)), 2);//just for simplification
float d = ((v * (cos(theta))/g)*((v * (sin(theta))+ sqrt(sqroot + sq))));
/*equation to calculate total distance covered
by the projectile. I started x from 0 and add 1 to it till it reaches d.for every value of x we get the
corisponding value of y from function coordinate.*/
ClearScreen();
while(x <= d)//loop to increment x
{
y = coordinate(theta, v, g, initialheight, x);
PlaceCursor(x, y); //using function from console.h and placing the cursor at (x, y) position
cout<<"*";
/*although the coordinates are stimulating the correct behavior of projectile but "* " are printing
an inverted projectile*/
x++;
}
system("pause");
return 0 ;
}
I believe the coordinate system for a console window starts at 0,0 in the top left and y increases down the window. Your code is correct, the graph itself is inverted because that's how the coords work.
I changed your code like this to get the desired result:
CONSOLE_SCREEN_BUFFER_INFO csbiInfo;
HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
GetConsoleScreenBufferInfo (hStdout, &csbiInfo);
int winheight = csbiInfo.dwSize.Y ;
system("cls");
while(x <= d)//loop to increment x
{
y = coordinate(theta, v, g, initialheight, x);
COORD pos;
pos.X = x;
pos.Y = winheight -y;
SetConsoleCursorPosition(hStdout, pos);
cout<<"*";
Without coding it up, this should fix it, change the value of gravity to a negative value in your equation as it's pulling in the opposite direction to your projectile.
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...
If I have a simple 2-D matrix with normalized values on x-axis between 0 and 1 and y-axys between 0 and 1, and I have 3 points in this matrix e.g. P1 (x=0.2,y=0.9), P2 (x=0.5,y=0.1) and P3 (x=0.9,y=0.4).
How can I simply calculate a curve thru this points, meaning having a function which is giving me the y for any x.
I now that there are any number of possible curves thru 3 points. But hey, you know what I mean: I want a smooth curve thru it, usable for audio-sample-interpolation, usable for calculation a volume-fade-curve, usable for calculating a monster-walking-path in a game.
Now I have searched the net for this question about 3 days, and I cannot believe that there is no usable solution for this task. All the text dealing about Catmull-rom-Splines, bezier-curves and all that theroretical stuff has all at least one point which doesn't make it for me usable. For example Catmull-Rom-splines need to have a fix distance between the control-points (I would use this code and set the 4. point-y to the 3. point y) :
void CatmullRomSpline(float *x,float *y,float x1,float y1,float x2,float y2,float x3,float y3,float x4,float y4,float u)
{
//x,y are calculated for x1,y1,x2,y2,x3,y3 and x4,y4 if u is the normalized distance (0-1) in relation to the distance between x2 and x3 for my whiched point
float u3,u2,f1,f2,f3,f4;
u3=u*u*u;
u2=u*u;
f1=-0.5f * u3 + u2 -0.5f *u;
f2= 1.5f * u3 -2.5f * u2+1.0f;
f3=-1.5f * u3 +2.0f * u2+0.5f*u;
f4=0.5f*u3-0.5f*u2;
*x=x1*f1+x2*f2+x3*f3+x4*f4;
*y=y1*f1+y2*f2+y3*f3+y4*f4;
}
But I don't see that x1 to x4 have any affect on the calculation of y, so I think x1 to x4 must have the same distance?
...
Or bezier-code doesn't calcuate the curve thru the points. The points (at least the 2. point) seem only to have a force-effect on the line.
typedef struct Point2D
{
double x;
double y;
} Point2D;
class bezier
{
std::vector<Point2D> points;
bezier();
void PushPoint2D( Point2D point );
Point2D GetPoint( double time );
~bezier();
};
void bezier::PushPoint2D(Point2D point)
{
points.push_back(point);
}
Point2D bezier::GetPoint( double x )
{
int i;
Point2D p;
p.x=0;
p.y=0;
if( points.size() == 1 ) return points[0];
if( points.size() == 0 ) return p;
bezier b;
for (i=0;i<(int)points.size()-1;i++)
{
p.x = ( points[i+1].x - points[i].x ) * x + points[i].x;
p.y = ( points[i+1].y - points[i].y ) * x + points[i].y;
if (points.size()<=2) return p;
b.PushPoint2D(p);
}
return b.GetPoint(x);
}
double GetLogicalYAtX(double x)
{
bezier bz;
Point2D p;
p.x=0.2;
p.y=0.9;
bz.PushPoint2D(p);
p.x=0.5;
p.y=0.1;
bz.PushPoint2D(p);
p.x=0.9;
p.y=0.4;
bz.PushPoint2D(p);
p=bz.GetPoint(x);
return p.y;
}
This is better than nothing, but it is 1. very slow (recursive) and 2. as I said doesn't really calculate the line thru the 2. point.
Is there a mathematical brain outside which could help me?
Thank you TOCS (Scott) for providing your code, I will also try it if I have some time. But what I have tested now is the hint by INFACT (answer 3): This "Largrange polynomials" are very very close to what I am searching for:
I have renamed my class bezier to curve, because I have added some code for lagrangeinterpolation. I also have added 3 pictures of graphical presentation what the code is calculation.
In Picture 1 you can see the loose middle point of the old bezier-function.
In Picture 2 you can now see the going thru all-points-result of lagrange interpolation.
In Picture 3 you can see the only problem, or should I say "thing which I also need to be solved" (anyway its the best solution till now): If I move the middle point, the curve to going to fast, to quick to the upper or lower boundaries). I would like it to go more smoothely to the upper and lower. So that it looks more logarithm-function like. So that it doesn't exeed the y-boundaries between 0 and 1 too soon.
Now my code looks like this:
curve::curve(void)
{
}
void curve::PushPoint2D(Point2D point)
{
points.push_back(point);
}
Point2D curve::GetPoint( double x )
{
//GetPoint y for x with bezier-mathematics...
//was the only calculating function in old class "bezier"
//now the class is renamed "curve"
int i;
Point2D p;
p.x=0;
p.y=0;
if( points.size() == 1 ) return points[0];
if( points.size() == 0 ) return p;
curve b;
for (i=0;i<(int)points.size()-1;i++)
{
p.x = ( points[i+1].x - points[i].x ) * x + points[i].x;
p.y = ( points[i+1].y - points[i].y ) * x + points[i].y;
if (points.size()<=2) return p;
b.PushPoint2D(p);
}
return b.GetPoint(x);
}
//THIS IS NEW AND VERY VERY COOL
double curve::LagrangeInterpolation(double x)
{
double y = 0;
for (int i = 0; i <= (int)points.size()-1; i++)
{
double numerator = 1;
double denominator = 1;
for (int c = 0; c <= (int)points.size()-1; c++)
{
if (c != i)
{
numerator *= (x - points[c].x);
denominator *= (points[i].x - points[c].x);
}
}
y += (points[i].y * (numerator / denominator));
}
return y;
}
curve::~curve(void)
{
}
double GetLogicalYAtX(double x)
{
curve cv;
Point2D p;
p.x=0; //always left edge
p.y=y1; //now by var
cv.PushPoint2D(p);
p.x=x2; //now by var
p.y=y2; //now by var
cv.PushPoint2D(p);
p.x=1; //always right edge
p.y=y3; //now by var
cv.PushPoint2D(p);
//p=cv.GetPoint(x);
//return p.y;
return cv.LagrangeInterpolation(x);
}
Do you have any ideas how I could get the new solution a little bit more "soft"? So that I can move the 2. Point in larger areas without the curve going out of boundaries? Thank you
static bezier From3Points(const Point2D &a, const Point2D &b, const Point2D &c)
{
bezier result;
result.PushPoint2D(a);
Point2D middle;
middle.x = 2*b.x - a.x/2 - c.x/2;
middle.y = 2*b.y - a.y/2 - c.y/2;
result.PushPoint2D(middle);
result.PushPoint2D(c);
return result;
}
Untested, but should return a bezier curve where at t=0.5 the curve passes through point 'b'.
Additionally (more untested code ahead), you can calculate your points using bernstein basis polynomials like so.
static int binomialcoefficient (int n, int k)
{
if (k == 0)
return 1;
if (n == 0)
return 0;
int result = 0;
for (int i = 1; i <= k; ++i)
{
result += (n - (k - i))/i;
}
return result;
}
static double bernstein (int v, int n, double t)
{
return binomialcoefficient(v,n) * pow(t,v) * pow(1 - t,n - v);
}
Point2D GetPoint (double t)
{
Point2D result;
result.x = 0;
result.y = 0;
for (int i = 0; i < points.size(); ++i)
{
double coeff = bernstein (i,points.size(),t);
result.x += coeff * points[i].x;
result.y += coeff * points[i].y;
}
return result;
}
I have written a program to approximate the solutions to ordinary differential equations using Adam's Method.
Running the program with gdb gives me:
Program received signal EXC_BAD_ACCESS, Could not access memory.
Reason: KERN_PROTECTION_FAILURE at address: 0x00007fff5f3ffff8
0x0000000100003977 in std::vector<double, std::allocator<double> >::push_back (this=0x100005420, __x=#0x100005310) at stl_vector.h:604
604 this->_M_impl.construct(this->_M_impl._M_finish, __x);
Clearly something is wrong with my treatment of vector.push_back, but I do not know where to begin looking. I can not think of a case where modifying a vector is illegal.
Call differentiate() to begin. Mathematics is done in step(). Adaptive time advancing across an interval with advance(). Check the chosen time step with checkdt() before running step() again.
Sorry for the huge code dump. I am sure many improvements can be made purely from the standpoint of C++, without knowledge of the mathematics:
//============================================================================
// Description : An Adam's Method Ordinary Differential Equation Approximation
// Disclaimer : Posted to StackOverflow for help on a segmentation fault
//============================================================================
#include <iostream> //IO
#include <vector> //std::vector
#include <cmath> //abs, pow, sqrt
#include <numeric> //accumulate
using namespace std;
/* Terminology:
* f(t, y) = the ordinary differential equation that will be solved
* y(t) = solution of f at point t.
* told = the previous point at which f was evaluated and solved
* tnow = the current point at which f is evaluated and solved
* tnew = the new (interesting) point at which f will be evaluated and solved
*
* Yold = the corrected solution of the differential equation at told
* Ynow = the corrected solution of the differential equation at tnow
* Ynew = the corrected solution of the differential equation at tnew
*
* fold = the value of the given differential equation at told
= f(told, Yold)
* fnow = the value of the given differential equation at tnow
= f(tnow, Ynow)
* fnew = the value of the given differential equation at tnew
= f(tnew, Ynew)
*
* Pnew = prediction for the value of Ynew
* dt = abs(tnew - tnow)
* dtold = abs(tnow - told)
*/
//Information storage
struct simTime {
double told;
double tnow;
double tnew;
double dt;
double dtold;
double tol;
double agrow;
double ashrink;
double dtmin;
double dtmax;
double endTime;
double fold;
double fnow;
double fnew;
double Yold;
double Ynow;
double Ynew;
double Pnew;
int stepsSinceRejection;
int stepsRejected;
int stepsAccepted;
} test;
//Define global variables
std::vector<double> errorIndicators(0);
std::vector<double> solutions(0);
std::vector<double> differencesDDY(0);
std::vector<double> differencesDDYSquared(0);
std::vector<double> timesTNew(0);
//Function declarations
void step(double fnow, double fold, double Ynow, double tnew, double tnow,
double dtold, double dt, double(*f)(double t, double y), double told);
void advance();
void shiftvariables();
void printvector(std::vector<double>& vec);
void differentiate(double(*f)(double t, double y), double y0, double a,
double b);
double f(double t, double y);
void checkdt();
int main() {
differentiate(f, 0, 1, 5);
cout << "Time values:" << endl;
printvector(timesTNew);
cout << "Solutions:" << endl;
printvector(solutions);
cout << "Differences between Prediction and Solution:" << endl;
printvector(differencesDDY);
return 0;
}
//Shift back all the variables to make way for the new values
void shiftvariables() {
test.tnow = test.tnew;
test.dtold = test.dt;
test.Yold = test.Ynow;
test.Ynow = test.Ynew;
test.fold = test.fnow;
test.fnow = test.fnew;
advance();
}
//Ordinary differential equation to be solved
double f(double t, double y) {
return pow(t, 2);
}
//Calculate the predicted and corrected solution at a chosen tnew
void step(double fnow, double fold, double Ynow, double tnew, double tnow,
double dtold, double dt, double(*f)(double t, double y), double told) {
//The calculation for Ynew requires integration. I first thought I would need to
// use my project 1 code to calculate the integration, but now I see in class we
// solved it analytically such that integration is not required:
//Linear prediction of Ynew using Ynow and fnow
double Pnew = Ynow + (dt * fnow) + (dt * dt / (2 * dtold)) * (fnow - fold);
test.Pnew = Pnew;
//Predict the value of f at tnew using Pnew
double fnew = f(tnew, Pnew);
test.fnew = fnew;
//Calculate the corrected solution at tnew
double interpolationFactor = fnew - (fnow + dt * (fnow - fold) / dtold);
double integration = (dt / 6) * (2 * dt + 3 * dtold) / (dt + dtold);
double Ynew = Pnew + interpolationFactor * integration;
test.Ynew = Ynew;
//Update the variables for the next round
shiftvariables();
}
//Check the previous solution and choose a new dt to continue evaluation
void advance() {
//The error indicator is the l2-norm of the prediction minus the correction
double err_ind = sqrt(
std::accumulate(differencesDDYSquared.begin(),
differencesDDYSquared.end(), 0));
errorIndicators.push_back(err_ind);
// Case where I reject the step and retry
if (err_ind > test.tol && test.dt > test.dtmin) {
++test.stepsRejected;
test.stepsSinceRejection = 0;
test.dt = test.dt * 0.5;
test.tnew = test.tnow + test.dt;
checkdt();
}
// Cases where I accept the step and move forward
else {
++test.stepsAccepted;
++test.stepsSinceRejection;
solutions.push_back(test.Ynew);
differencesDDY.push_back(abs(test.Pnew - test.Ynew));
differencesDDYSquared.push_back(pow((test.Pnew - test.Ynew), 2));
//Decrease dt
if (err_ind >= 0.75 * test.tol) {
test.dtold = test.dt;
test.dt = (test.dt * test.ashrink);
test.tnew = test.tnow + test.dt;
checkdt();
}
//Increase dt
else if (err_ind <= test.tol / 4) {
if ((test.stepsRejected != 0) && (test.stepsSinceRejection >= 2)) {
test.dt = (test.dt * test.agrow);
test.tnew = test.tnow + test.dt;
checkdt();
} else if (test.stepsRejected == 0) {
test.dt = (test.dt * test.agrow);
test.tnew = test.tnow + test.dt;
checkdt();
}
}
}
}
//Check that the dt chosen by advance is acceptable
void checkdt() {
if ((test.tnew < test.endTime) && (test.endTime - test.tnew < test.dtmin)) {
cout << "Reached endTime." << endl;
} else if (test.dt < test.dtmin) {
test.dt = test.dtmin;
test.tnew = test.tnow + test.dt;
timesTNew.push_back(test.tnew);
step(test.fnow, test.fold, test.Ynow, test.tnew, test.tnow, test.dtold,
test.dt, f, test.told);
} else if (test.dt > test.dtmax) {
test.dt = test.dtmax;
test.tnew = test.tnow + test.dt;
timesTNew.push_back(test.tnew);
step(test.fnow, test.fold, test.Ynow, test.tnew, test.tnow, test.dtold,
test.dt, f, test.told);
} else if ((test.tnew + test.dt) > test.endTime) {
test.dt = test.endTime - test.tnew;
test.tnew = test.tnow + test.dt;
checkdt();
} else if (((test.tnew + test.dt) < test.endTime)
&& ((test.tnew + 2 * test.dt) > test.endTime)) {
test.dt = (test.endTime - test.tnew) / 2;
test.tnew = test.tnow + test.dt;
checkdt();
}
//If none of the above are satisfied, then the chosen dt
// is ok and proceed with it
else {
timesTNew.push_back(test.tnew);
step(test.fnow, test.fold, test.Ynow, test.tnew, test.tnow, test.dtold,
test.dt, f, test.told);
}
}
//meta function to solve a differential equation, called only once
void differentiate(double(*f)(double t, double y), double y0, double a,
double b) {
//Set the starting conditions for the solving of the differential equation
test.fnow = f(a, y0);
test.endTime = b;
test.Ynow = y0;
//solutions.push_back(y0);
timesTNew.push_back(a);
//Set the constants
test.ashrink = 0.8;
test.agrow = 1.25;
test.dtmin = 0.05;
test.dtmax = 0.5;
test.tol = 0.1;
//Set fold = fnow for the first step
test.fold = test.fnow;
test.tnow = a;
test.told = a - test.dtmin;
test.dtold = abs(test.tnow - test.told);
//Create the first prediction, which will then lead to correcting it with step
advance();
}
// Takes a vector as its only parameters and prints it to stdout
void printvector(std::vector<double>& vec) {
for (vector<double>::iterator it = vec.begin(); it != vec.end(); ++it) {
cout << *it << ", ";
}
cout << "\n";
}
Thank you.
Since you're using recursion, could it be possible that you are running out of stack memory, thus causing the segfault? This could happen if either your app recurses too many times or if some bug causes it to recurse infinitely.
Note, as sth suggests in a comment, a debugger may help you decide whether or not this is the case.