I'm running a program that preforms a Euler Approximation of an Ordinary Differential Equation. The smaller the step size that is chosen, the more accurate the approximation is. I can get it to work for a set step size using this code:
#include <iostream>
using std::cout;
double f (double x, double t)
{
return t*x*x-t;
}
int main()
{
double x=0.0,t=0.0,t1=2.0;
int n=20;
double h = (t1-t) / double(n);
// ----- EULERS METHOD
for (int i=0; i<n; i++)
{
x += h*f(x,t);
t += h;
}
cout << h << " " << x << "\n";
}
So this code runs a Eulers approximation for n=20 which corresponds to a step size of 0.1 and outputs the step size along with the approximation for x(2). I want top know how to loop this code (for different values of n) so that it outputs this followed by increasingly smaller step sizes with corresponding approximations.
i.e an output something like this:
0.1 -0.972125
0.01 -0.964762
0.001 -0.9641
etc.
So I tried a for-loop inside a for-loop but its giving me a weird output of extreme values.
#include <iostream>
using std::cout;
double f (double x, double t)
{
return t*x*x-t;
}
int main()
{
double x=0.0,t=0.0,t1=2.0;
for (int n=20;n<40;n++)
{
double h = (t1-t)/n;
for (int i=0;i<n;i++)
{
x += h*f(x,t);
t += h;
}
cout << h << " " << x << "\n";
}
}
If I understand correctly, you want to execute that first piece of code inside your main function for different values of n. Then your problem is with the variables x, t and t1, which are set once before the loop and never reset. You want them inside your outer loop:
#include <iostream>
using std::cout;
double f( double x, double t )
{
return t * x * x - t;
}
int main()
{
for ( int n = 20; n < 40; n++ )
{
double x = 0.0, t = 0.0, t1 = 2.0;
double h = ( t1 - t ) / n;
for ( int i = 0; i < n; i++ )
{
x += h * f( x, t );
t += h;
}
cout << h << " " << x << "\n";
}
}
Using a function for this, makes it clearer:
#include <iostream>
using std::cout;
double f( double x, double t )
{
return t * x * x - t;
}
void eulers( const int n )
{
double x = 0.0, t = 0.0, t1 = 2.0;
double h = ( t1 - t ) / n;
for ( int i = 0; i < n; i++ )
{
x += h * f( x, t );
t += h;
}
cout << h << " " << x << "\n";
}
int main()
{
for ( int n = 20; n < 40; n++ )
{
eulers( n );
}
}
Hope this helps.
Related
So the value that im getting is "nan" and i suspect something is wrong in my while statement.
#include <iostream>
#include <math.h>
using namespace std;
int main()
{ int n=1,c=0;
float x;
double sum=0, old_sum, diff=1000000,eps;
cin>>x>>eps;
while(abs(diff)>=eps){
old_sum=sum;
sum=sum+double(pow(x,n)/n)*double(pow(-1,c));
c++;
n+=2;
diff=sum-old_sum;
}
cout<<sum<<"\n";
cout<<atan(x);
return 0;
}
My input is 21 for x and 0.01 for eps and what i get is nan and the correct value done by the atan function.
There are several issues in your code:
You don't take into account that the formula is only valid for abs(x) <= 1. This can be solved by a little mathematical trick
You don't check that the formula converges effectively. This can be done with a test of the value of n
You are repetidly using the pow(.) function. This is useless. This doesn't provide bad results, but it is quite inefficient
#include <iostream>
#include <cmath>
int main() {
int n = 3;
int n_max = 200;
double x;
double eps;
std::cin >> x >> eps;
double x_sav = x;
x = x / (1.0 + sqrt(1+x*x)); // the trick to handle abs(x) > 1
int sign = -1;
double term = x;
double powerx = x;
double sum = x;
double x2 = x*x;
while (std::abs(term) > eps && n <= n_max) {
powerx *= x2;
term = powerx / n;
sum += term * sign;
n += 2;
sign = -sign;
}
if (n > n_max) {
std::cout << "The series did not converge\n";
return 1;
}
sum *= 2.0; // following of the trick
std::cout << sum << "\n";
std::cout << atan(x_sav) << "\n";
return 0;
}
I made a function that makes the inverse and then another multithreaded, as long I have to make inverse of arrays >2000 x 2000.
A 1000x1000 array unthreated takes 2.5 seconds (on a i5-4460 4 cores 2.9ghz)
and multithreaded takes 7.25 seconds
I placed the multithreads in the part that most time consumption is taken. Whai is wrong?
Is due vectors are used instead of 2 dimensions arrays?
This is the minimum code to test both versions:
#include<iostream>
#include <vector>
#include <stdlib.h>
#include <time.h>
#include <chrono>
#include <thread>
const int NUCLEOS = 8;
#ifdef __linux__
#include <unistd.h> //usleep()
typedef std::chrono::system_clock t_clock; //try to use high_resolution_clock on new linux x64 computer!
#else
typedef std::chrono::high_resolution_clock t_clock;
#pragma warning(disable:4996)
#endif
using namespace std;
std::chrono::time_point<t_clock> start_time, stop_time = start_time; char null_char = '\0';
void timer(char *title = 0, int data_size = 1) { stop_time = t_clock::now(); double us = (double)chrono::duration_cast<chrono::microseconds>(stop_time - start_time).count(); if (title) printf("%s time = %7lgms = %7lg MOPs\n", title, (double)us*1e-3, (double)data_size / us); start_time = t_clock::now(); }
//makes columns 0
void colum_zero(vector< vector<double> > &x, vector< vector<double> > &y, int pos0, int pos1,int dim, int ord);
//returns inverse of x, x is not modified, not threaded
vector< vector<double> > inverse(vector< vector<double> > x)
{
if (x.size() != x[0].size())
{
cout << "ERROR on inverse() not square array" << endl; getchar(); return{};//returns a null
}
size_t dim = x.size();
int i, j, ord;
vector< vector<double> > y(dim,vector<double>(dim,0));//initializes output = 0
//init_2Dvector(y, dim, dim);
//1. Unity array y:
for (i = 0; i < dim; i++)
{
y[i][i] = 1.0;
}
double diagon, coef;
double *ptrx, *ptry, *ptrx2, *ptry2;
for (ord = 0; ord<dim; ord++)
{
//2 Hacemos diagonal de x =1
int i2;
if (fabs(x[ord][ord])<1e-15) //If that element is 0, a line that contains a non zero is added
{
for (i2 = ord + 1; i2<dim; i2++)
{
if (fabs(x[i2][ord])>1e-15) break;
}
if (i2 >= dim)
return{};//error, returns null
for (i = 0; i<dim; i++)//added a line without 0
{
x[ord][i] += x[i2][i];
y[ord][i] += y[i2][i];
}
}
diagon = 1.0/x[ord][ord];
ptry = &y[ord][0];
ptrx = &x[ord][0];
for (i = 0; i < dim; i++)
{
*ptry++ *= diagon;
*ptrx++ *= diagon;
}
//uses the same function but not threaded:
colum_zero(x,y,0,dim,dim,ord);
}//end ord
return y;
}
//threaded version
vector< vector<double> > inverse_th(vector< vector<double> > x)
{
if (x.size() != x[0].size())
{
cout << "ERROR on inverse() not square array" << endl; getchar(); return{};//returns a null
}
int dim = (int) x.size();
int i, ord;
vector< vector<double> > y(dim, vector<double>(dim, 0));//initializes output = 0
//init_2Dvector(y, dim, dim);
//1. Unity array y:
for (i = 0; i < dim; i++)
{
y[i][i] = 1.0;
}
std::thread tarea[NUCLEOS];
double diagon;
double *ptrx, *ptry;// , *ptrx2, *ptry2;
for (ord = 0; ord<dim; ord++)
{
//2 Hacemos diagonal de x =1
int i2;
if (fabs(x[ord][ord])<1e-15) //If a diagonal element=0 it is added a column that is not 0 the diagonal element
{
for (i2 = ord + 1; i2<dim; i2++)
{
if (fabs(x[i2][ord])>1e-15) break;
}
if (i2 >= dim)
return{};//error, returns null
for (i = 0; i<dim; i++)//It is looked for a line without zero to be added to make the number a non zero one to avoid later divide by 0
{
x[ord][i] += x[i2][i];
y[ord][i] += y[i2][i];
}
}
diagon = 1.0 / x[ord][ord];
ptry = &y[ord][0];
ptrx = &x[ord][0];
for (i = 0; i < dim; i++)
{
*ptry++ *= diagon;
*ptrx++ *= diagon;
}
int pos0 = 0, N1 = dim;//initial array position
if ((N1<1) || (N1>5000))
{
cout << "It is detected out than 1-5000 simulations points=" << N1 << " ABORT or press enter to continue" << endl; getchar();
}
//cout << "Initiation of " << NUCLEOS << " threads" << endl;
for (int thread = 0; thread<NUCLEOS; thread++)
{
int pos1 = (int)((thread + 1)*N1 / NUCLEOS);//next position
tarea[thread] = std::thread(colum_zero, std::ref(x), std::ref(y), pos0, pos1, dim, ord);//ojo, coil current=1!!!!!!!!!!!!!!!!!!
pos0 = pos1;//next thread will work at next point
}
for (int thread = 0; thread<NUCLEOS; thread++)
{
tarea[thread].join();
//cout << "Thread num: " << thread << " end\n";
}
}//end ord
return y;
}
//makes columns 0
void colum_zero(vector< vector<double> > &x, vector< vector<double> > &y, int pos0, int pos1,int dim, int ord)
{
double coef;
double *ptrx, *ptry, *ptrx2, *ptry2;
//Hacemos '0' la columna ord salvo elemento diagonal:
for (int i = pos0; i<pos1; i++)//Begin to end for every thread
{
if (i == ord) continue;
coef = x[i][ord];//element to make 0
if (fabs(coef)<1e-15) continue; //If already zero, it is avoided
ptry = &y[i][0];
ptry2 = &y[ord][0];
ptrx = &x[i][0];
ptrx2 = &x[ord][0];
for (int j = 0; j < dim; j++)
{
*ptry++ = *ptry - coef * (*ptry2++);//1ª matriz
*ptrx++ = *ptrx - coef * (*ptrx2++);//2ª matriz
}
}
}
void test_6_inverse(int dim)
{
vector< vector<double> > vec1(dim, vector<double>(dim));
for (int i=0;i<dim;i++)
for (int j = 0; j < dim; j++)
{
vec1[i][j] = (-1.0 + 2.0*rand() / RAND_MAX) * 10000;
}
vector< vector<double> > vec2,vec3;
double ini, end;
ini = (double)clock();
vec2 = inverse(vec1);
end = (double)clock();
cout << "=== Time inverse unthreaded=" << (end - ini) / CLOCKS_PER_SEC << endl;
ini=end;
vec3 = inverse_th(vec1);
end = (double)clock();
cout << "=== Time inverse threaded=" << (end - ini) / CLOCKS_PER_SEC << endl;
cout<<vec2[2][2]<<" "<<vec3[2][2]<<endl;//to make the sw to do de inverse
cout << endl;
}
int main()
{
test_6_inverse(1000);
cout << endl << "=== END ===" << endl; getchar();
return 1;
}
After looking deeper in the code of the colum_zero() function I have seen that one thread rewrites in the data to be used by another threads, so the threads are not INDEPENDENT from each other. Fortunately the compiler detect it and avoid it.
Conclusions:
It is not recommended to try Gauss-Jordan method alone to make multithreads
If somebody detects that in multithread is slower and the initial function is spreaded correctly for every thread, perhaps is due one thread results are used by another
The main function inverse() works and can be used by other programmers, so this question should not be deleted
Non answered question:
What is a matrix inverse method that could be spreaded in a lot of independent threads to be used in a gpu?
The following error message was received after running my code located at the end of the message:
terminate called after throwing an instance of 'std::out_of_range'
what(): vector::_M_range_check: __n (which is 0) >= this->size() (which is 0)
This application has requested the Runtime to terminate it in an unusual way.
Please contact the application's support team for more information.
I'm sorry for the length of the code. It appears that the error is coming from when I am calling the numerov function within the f function. If you are able to determine what the error is would you please let me know? Thank you!
#include <iostream>
#include <cmath>
#include <fstream>
#include <vector>
using namespace std;
int nx = 500, m = 10, ni = 10;
double x1 = 0, x2 = 1, h = (x2 - x1)/nx;
int nr, nl;
vector<double> ul, q, u;
//Method to achieve the evenly spaced Simpson rule
double simpson(vector <double> y, double h)
{
int n = y.size() - 1;
double s0 = 0, s1 = 0, s2 = 0;
for (int i = 1; i < n; i += 2)
{
s0 += y.at(i);
s1 += y.at(i-1);
s2 += y.at(i+1);
}
double s = (s1 + 4*s0 + s2)/3;
//Add the last slice separately for an even n+1
if ((n+1)%2 == 0)
return h*(s + (5*y.at(n) + 8*y.at(n-1) - y.at(n-2))/12);
else
return h*2;
}
//Method to perform the Numerov integration
vector <double> numerov(int m, double h, double u0, double u1, double q)
{
vector<double> u;
u.push_back(u0);
u.push_back(u1);
double g = h*h/12;
for (int i = 1; i < m+1; i++)
{
double c0 = 1 + g*q;
double c1 = 2 - 10*g*q;
double c2 = 1 + g*q;
double d = g*(0);
u.push_back((c1*u.at(i) - c0*u.at(i-1) + d)/c2);
}
return u;
}
//Method to provide the function for the root search
double f(double x)
{
vector<double> w;
vector<double> j = numerov(nx + 1, h, 0.0, 0.001, x);
for (int i = 0; i < 0; i++)
{
w.push_back(j.at(i));
}
return w.at(0);
}
//Method to carry out the secant search
double secant(int n, double del, double x, double dx)
{
int k = 0;
double x1 = x + dx;
while ((abs(dx) > del) && (k < n))
{
double d = f(x1) - f(x);
double x2 = x1 - f(x1)*(x1 - x)/d;
x = x1;
x1 = x2;
dx = x1 - x;
k++;
}
if (k == n)
cout << "Convergence not found after " << n << " iterations." << endl;
return x1;
}
int main()
{
double del = 1e-6, e = 0, de = 0.1;
//Find the eigenvalue via the secant method
e = secant (ni, del, e, de);
//Find the solution u(x)
u = numerov(nx + 1, h, 0.0, 0.01, e);
//Output the wavefunction to a file
ofstream myfile ("Problem 2.txt");
if (myfile.is_open())
{
myfile << "Input" << "\t" << "u(x)" << endl;
double x = x1;
double mh = m*h;
for (int i = 0; i <= nx; i += m)
{
myfile << x << "\t" << u.at(i) << endl;
x += mh;
}
myfile.close();
}
return 0;
}
vector<double> w;
for (int i = 0; i < 0; i++)
{
w.push_back(j.at(i));
}
return w.at(0);
w will have nothing in it, since that loop will run 0 times. Thus, w.at(0) will throw the out of range error.
Why do you think the problem is in the numerov function?
I see an error in the function f?
vector<double> w;
vector<double> j = numerov(nx + 1, h, 0.0, 0.001, x);
for (int i = 0; i < 0; i++)
{
w.push_back(j.at(i));
}
return w.at(0);
There is nothing on vector w and you try to access element 0.
In my code, I'm trying to prevent circles from overlapping so I specified it as a condition on the distance between the centres of the circles but it seems to not work all the time
as you can see :
could it be some kind of numerical precision rounding problem ?
Here is the relevant code (I can post the whole code if needed):
const double win_size = 800;
const double L = 50e-9; //box size (m)
const double k = 1.38e-23; // Boltzmann constant = 1.38e-23 J/K
const double R = 1.6e-10*30; //N2 radius = 1.6e-10 m
const double m = 4.65e-26; //N2 mass = 4.65e-26 kg
struct parameters{
double x;
double y;
double v_x;
double v_y;
};
bool empty_space(double x, double y, struct parameters gas[], int N, int i){
if (i == 0) return true;
for (int i = 0; i<N; i++){
if (pow(x-gas[i].x,2) + pow(y-gas[i].y,2) <= 4*R*R){
cout << gas[i].x << " " << gas[i].y << endl;
return false;
}
}
return true;
}
void initialize(struct parameters gas[], int N, double T){ // Sets initial conditions (velocity depends on temperature)
int tries = 0;
double x, y;
for (int i=0; i<N; i++){
if (tries == 10000){
cout << "Couldn't fit " << N << " molecules in the box, aborting simulation... " << endl;
exit(1);
}
x = R + (L - 2*R)*rand()/RAND_MAX;
y = R + (L - 2*R)*rand()/RAND_MAX;
if (empty_space(x,y,gas,N,i)){
gas[i].x = x;
gas[i].y = y;
}
else {
i--;
tries++;
}
gas[i].v_x = sqrt(2*k*T/m)*(1-2.0*rand()/RAND_MAX);
gas[i].v_y = (2*(rand()%2) - 1)*sqrt(2*k*T/m - pow(gas[i].v_x, 2));
}
}
void draw(int window, struct parameters gas[], int N, int automatic){
g2_pen(window,g2_ink(window,0.8,0.3,0.4));
for (int i=0; i<N; i++){
g2_circle(window,gas[i].x*win_size/L,gas[i].y*win_size/L,R*win_size/L);
}
g2_flush(window);
usleep(10000);
g2_pen(window,0);
g2_filled_rectangle(window,0,0,win_size,win_size);
if (!automatic) getchar();
}
The first debugging step is to print the coordinates of the circles that have clashed somehow, then see what the "distance" function is returning for their centers. My guess it it's somehow a rounding problem but this seems to be what you need to do next.
Here is my code so far. There seems to be soemthing wrong since I keep getting an incorrect answer. I am writing in a text file that is formatted:
2
3.0 1.0
2 being the size of the array and then 3.0 and 1.0 being the coefficients. Hopefully I didnt miss much in my explanation. Any help would be greatly appreciated.
Thanks
double polyeval(double* polyarray, double x, int arraySize)
{
//int result = 0;
if(arraySize == 0)
{
return polyarray[arraySize];
}
//result += x*(polyarray[arraySize]+polyeval(polyarray,x,arraySize-1));
return polyarray[arraySize-1]+ (x* (polyeval(polyarray,x,arraySize-1)));
//return result;
}
int main ()
{
int arraySize;
double x;
double *polyarray;
ifstream input;
input.open("polynomial.txt");
input >> arraySize;
polyarray = new double [arraySize];
for (int a = arraySize - 1; a >= 0; a--)
{
input >> polyarray[a];
}
cout << "For what value x would you like to evaluate?" << endl;
cin >> x;
cout << "Polynomial Evaluation: " << polyeval(polyarray, x, arraySize);
delete [] polyarray;
}
the idea that if i read in a text file of that format varying in size that it will solve for any value x given by the user
Jut taking a wild guess
for (int a = arraySize - 1; a >= 0; a--)
// ^^
{
input >> polyarray[a];
}
One error is here:
for (int a = arraySize - 1; a > 0; a--)
{ //^^should be a >=0
input >> polyarray[a];
}
You are missing some entry this way.
The recursive function should look like the following:
int polyeval(double* polyarray, double x, int arraySize)
{
if(arraySize == 1)
{
return polyarray[arraySize-1];
}
return x*(polyarray[arraySize-1]+polyeval(polyarray,x,arraySize-1));
}
The problem is mainly with the definition of the polynomial coefficients.
Your code assumes a polynomial on the form:
x( p(n) + x( p(n-1) + x( p(n-2) + ... x(p(1) + p(0)))..))
This line:
result += x*(polyarray[arraySize]+polyeval(polyarray,x,arraySize-1));
Should become:
result += pow(x,arraySize)*polyarray[arraySize]+polyeval(polyarray,x,arraySize-1);
This way the polynomial is defined correctly as p(n)x^n + p(n-1)x^(n-1) ... + p1 x + p0
Couldn't work out exactly what you were trying to do, or why you were using recursion. So I whipped up a non-recursive version that seems to give the right results.
#include <iostream>
using namespace std;
double polyeval(const double* polyarray, double x, int arraySize) {
if(arraySize <= 0) { return 0; }
double value = 0;
const double * p = polyarray + (arraySize-1);
for(int i=0; i<arraySize; ++i) {
value *= x;
value += *p;
p--;
}
return value;
}
int main () {
const int arraySize = 3;
const double polyarrayA[3] = {0.0,0.0,1.0}; // 0 + 0 x + 1 x^2
const double polyarrayB[3] = {0.0,1.0,0.0}; // 0 + 1 x + 0 x^2
const double polyarrayC[3] = {1.0,0.0,0.0}; // 1 + 0 x + 0 x^2
cout << "Polynomial Evaluation A f(x) = " << polyeval(polyarrayA, 0.5, arraySize)<<std::endl;
cout << "Polynomial Evaluation B f(x) = " << polyeval(polyarrayB, 0.5, arraySize)<<std::endl;
cout << "Polynomial Evaluation C f(x) = " << polyeval(polyarrayC, 0.5, arraySize)<<std::endl;
}
You can see it running here:
http://ideone.com/HE4r6x