Related
2nd task:
For a function f : R^n → R the gradient at a point ~x ∈ R^n is to be calculated:
- Implement a function
CMyVector gradient(CMyVector x, double (*function)(CMyVector x)),
which is given in the first parameter the location ~x and in the second parameter the function f as function pointer in the second parameter, and which calculates the gradient ~g = grad f(~x) numerically
by
gi = f(x1, . . . , xi-1, xi + h, xi+1 . . . , xn) - f(x1, . . . , xn)/h
to fixed h = 10^-8.
My currently written program:
Header
#pragma once
#include <vector>
#include <math.h>
class CMyVektor
{
private:
/* data */
int Dimension = 0;
std::vector<double>Vector;
public:
CMyVektor();
~CMyVektor();
//Public Method
void set_Dimension(int Dimension /* Aktuelle Dim*/);
void set_specified_Value(int index, int Value);
double get_specified_Value(int key);
int get_Vector_Dimension();
int get_length_Vektor();
double& operator [](int index);
string umwandlung()
};
CMyVektor::CMyVektor(/* args */)
{
Vector.resize(0, 0);
}
CMyVektor::~CMyVektor()
{
for (size_t i = 0; i < Vector.size(); i++)
{
delete Vector[i];
}
}
void CMyVektor::set_Dimension(int Dimension /* Aktuelle Dim*/)
{
Vector.resize(Dimension);
};
void CMyVektor::set_specified_Value(int index, int Value)
{
if (Vector.empty())
{
Vector.push_back(Value);
}
else {
Vector[index] = Value;
}
};
double CMyVektor::get_specified_Value(int key)
{
// vom intervall anfang - ende des Vectors
for (unsigned i = 0; i < Vector.size(); i++)
{
if (Vector[i] == key) {
return Vector[i];
}
}
};
int CMyVektor::get_Vector_Dimension()
{
return Vector.size();
};
// Berechnet den Betrag "länge" eines Vectors.
int CMyVektor::get_length_Vektor()
{
int length = 0;
for (size_t i = 0; i < Vector.size(); i++)
{
length += Vector[i]^2
}
return sqrt(length);
}
// [] Operator überladen
double& CMyVektor::operator [](int index)
{
return Vector[index];
}
main.cpp
#include <iostream>
#include "ClassVektor.h"
using namespace std;
CMyVektor operator+(CMyVektor a, CMyVektor b);
CMyVektor operator*(double lambda, CMyVektor a);
CMyVektor gradient(CMyVektor x, double (*funktion)(CMyVektor x));
int main() {
CMyVektor V1;
CMyVektor V2;
CMyVektor C;
C.set_Dimension(V1.get_length_Vector());
C= V1 + V2;
std::cout << "Addition : "<< "(";;
for (int i = 0; i < C.get_length_Vector(); i++)
{
std::cout << C[i] << " ";
}
std::cout << ")" << endl;
C = lamda * C;
std::cout << "Skalarprodukt: "<< C[0]<< " ";
}
// Vector Addition
CMyVektor operator+(CMyVektor a, CMyVektor b)
{
int ai = 0, bi = 0;
int counter = 0;
CMyVektor c;
c.set_Dimension(a.get_length_Vector());
// Wenn Dimension Gleich dann addition
if (a.get_length_Vector() == b.get_length_Vector())
{
while (counter < a.get_length_Vector())
{
c[counter] = a[ai] + b[bi];
counter++;
}
return c;
}
}
//Berechnet das Skalarprodukt
CMyVektor operator*(double lambda, CMyVektor a)
{
CMyVektor c;
c.set_Dimension(1);
for (unsigned i = 0; i < a.get_length_Vector(); i++)
{
c[0] += lambda * a[i];
}
return c;
}
/*
* Differenzenquotient : (F(x0+h)+F'(x0)) / h
* Erster Parameter die Stelle X - Zweiter Parameter die Funktion
* Bestimmt numerisch den Gradienten.
*/
CMyVektor gradient(CMyVektor x, double (*funktion)(CMyVektor x))
{
}
My problem now is that I don't quite know how to deal with the
CMyVector gradient(CMyVector x, double (*function)(CMyVector x))
function and how to define a function that corresponds to it.
I hope that it is enough information. Many thanks.
The function parameter is the f in the difference formula. It takes a CMyVector parameter x and returns a double value. You need to supply a function parameter name. I'll assume func for now.
I don't see a parameter for h. Are you going to pass a single small value into the gradient function or assume a constant?
The parameter x is a vector. Will you add a constant h to each element?
This function specification is a mess.
Function returns a double. How do you plan to turn that into a vector?
No wonder you're confused. I am.
Are you trying to do something like this?
You are given a function signature
CMyVector gradient(CMyVector x, double (*function)(CMyVector x))
Without knowing the exact definition I will assume, that at least the basic numerical vector operations are defined. That means, that the following statements compile:
CMyVector x {2.,5.,7.};
CMyVector y {1.,7.,4.};
CMyVector z {0.,0.,0.};
double a = 0.;
// vector addition and assigment
z = x + y;
// vector scalar multiplication and division
z = z * a;
z = x / 0.1;
Also we need to know the dimension of the CMyVector class. I assumed and will continue to do so that it is three dimensional.
The next step is to understand the function signature. You get two parameters. The first one denotes the point, at which you are supposed to calculate the gradient. The second is a pointer to the function f in your formula. You do not know it, but can call it on a vector from within your gradient function definition. That means, inside of the definition you can do something like
double f_at_x = function(x);
and the f_at_x will hold the value f(x) after that operation.
Armed with this, we can try to implement the formula, that you mentioned in the question title:
CMyVector gradient(CMyVector x, double (*function)(CMyVector x)) {
double h = 0.001;
// calculate first element of the gradient
CMyVector e1 {1.0, 0.0, 0.0};
double result1 = ( function(x + e1*h) - function(x) )/h;
// calculate second element of the gradient
CMyVector e2 {0.0, 1.0, 0.0};
double result2 = ( function(x + e2*h) - function(x) )/h;
// calculate third element of the gradient
CMyVector e3 {0.0, 0.0, 1.0};
double result3 = ( function(x + e3*h) - function(x) )/h;
// return the result
return CMyVector {result1, result2, result3};
}
There are several thing worth to mention in this code. First and most important I have chosen h = 0.001. This may like a very arbitrary choice, but the choice of the step size will very much impact the precision of your result. You can find a whole lot of discussion about that topic here. I took the same value that according to that wikipedia page a lot of handheld calculators use internally. That might not be the best choice for the floating point precision of your processor, but should be a fair one to start with.
Secondly the code looks very ugly for an advanced programmer. We are doing almost the same thing for each of the three dimensions. Ususally you would like to do that in a for loop. The exact way of how this is done depends on how the CMyVector type is defined.
Since the CMyVektor is just rewritting the valarray container, I will directly use the valarray:
#include <iostream>
#include <valarray>
using namespace std;
using CMyVektor = valarray<double>;
CMyVektor gradient(CMyVektor x, double (*funktion)(CMyVektor x));
const double h = 0.00000001;
int main()
{
// sum(x_i^2 + x_i)--> gradient: 2*x_i + 1
auto fun = [](CMyVektor x) {return (x*x + x).sum();};
CMyVektor d = gradient(CMyVektor{1,2,3,4,5}, fun);
for (auto i: d) cout << i<<' ';
return 0;
}
CMyVektor gradient(CMyVektor x, double (*funktion)(CMyVektor x)){
CMyVektor grads(x.size());
CMyVektor pos(x.size());
for (int i = 0; i<x.size(); i++){
pos[i] = 1;
grads[i] = (funktion(x + h * pos) - funktion(x))/ h;
pos[i] = 0;
}
return grads;
}
The prints out 3 5 7 9 11 which is what is expected from the given function and the given location
To describe the problem, I am trying to use objects in my code to stream line a three body problem. I have the following code for the object:
#include <stdlib.h>
#include <cstdio>
#include <iostream>
#include <cmath>
#include <vector>
#include "star.h"
using namespace std;
Star::Star( double m, double x_p, double y_p, double x_v, double y_v )
{
init( m, x_p, y_p, x_v, y_v);
}
void Star::init( double m, double x_p, double y_p, double x_v, double y_v )
{
Mass = m;
X_Position = x_p;
Y_Position = y_p;
X_Velocity = x_v;
Y_Velocity = y_v;
R_Position[0] = X_Position;
R_Position[1] = Y_Position;
R_Velocity[0] = X_Velocity;
R_Velocity[1] = Y_Velocity;
}
double Star::potential( Star star2, double dx, double dy )
{
double G = 3.0548e34;
double Potential;
double x_component = X_Position - star2.X_Position + dx;
double y_component = Y_Position - star2.Y_Position + dy;
double R = sqrt(x_component*x_component + y_component*y_component);
Potential = G* Mass* star2.Mass / R;
return Potential;
}
double * Star::compute_forces( Star star2 )
{
double h_x = ( X_Position - star2.X_Position )/1000;
double h_y = ( Y_Position - star2.Y_Position )/1000;
double *F = new double[2];
F[0] = ( potential( star2, h_x, 0.0 ) - potential( star2, -h_x, 0.0 ) )/2*h_x;
F[1] = ( potential( star2, 0.0, h_y ) - potential( star2, 0.0, -h_y ) )/2*h_y;
return F;
}
void Star::verlet( Star star2, double h )
{
double *Force = compute_forces( star2 );
X_Position += h*X_Velocity + 0.5*h*h*Force[ 0 ];
Y_Position += h*Y_Velocity + 0.5*h*h*Force[ 1 ];
double *Force_new = compute_forces( star2 );
X_Velocity += 0.5*h*(Force[ 0 ] + Force_new[ 0 ] );
Y_Velocity += 0.5*h*(Force[ 1 ] + Force_new[ 1 ] );
}
Now I believe that the velocity verlet algorithm is correct, but when I run the code using this main file:
#include <iostream>
#include <fstream>
#include <cmath>
#include <cstdio>
#include "star.h"
using namespace std;
int main()
{
Star star1( 50, 0.0, 0.0, 0.0, 0.0 );
Star star2( 1.00, 0.0, 1.0, -1.0, 1.0 );
Star star3( 1.00, 0.0, -1.0, 1.0, 1.0 );
Star arr[3] = { star1, star2, star3 };
double h = 10/1000;
//for ( double time = 0.0; time <= 10.0; )
//{
for ( int inst = 0 ; inst< 3; ++inst )
{
for ( int jnst = 0; jnst < 3; ++jnst )
{
if ( inst != jnst )
{
arr[ inst ].verlet( arr[ jnst ], h );
double *pos = arr[ inst ].get_positions();
cout << " " << pos[ 0 ] << " " << pos[ 1 ] << endl;
}
}
}
//time += h;
//}
return 0;
}
The values of members of the Star object are not updating :/. Is there something I am missing?
the out put of the cout is this:
0 0
0 0
0 1
0 1
0 -1
0 -1
Thank you in advance!
Edit:
I tried implementing a std::vector<double> for my forces, but I ended up with a segmentation fault.
Edit 2:
After checking my get_positions() method I noticed it was returning only the initialized values. So I tried implementing this:
std::vector<double> get_positions(){ std::vector<double> temp = { X_Position , Y_Position }; return temp; }
And it worked so i implemented the following into my main code.
std::vector<double> p1 = star1.get_positions();
std::vector<double> p2 = star2.get_positions();
std::vector<double> p3 = star3.get_positions();
cout << p1[ 0 ] << " " << p1[ 1 ] << " " << p2[ 0 ] << " " << p2[ 1 ] << " " << p3[ 0 ] << " " << p3[ 1 ] << endl;
However now I am stuck on a completely new problem... Now I am getting the following numbers for the algorithm updates!
5.66002e-320 2.31834e-316
1.132e-316 4.63669e-313
1.698e-319 6.95503e-316
1.132e-316 4.63669e-313
5.66002e-320 2.31834e-316
1.132e-316 4.63669e-313
1.698e-319 6.95503e-316
1.132e-316 4.63669e-313
5.66002e-320 2.31834e-316
1.132e-316 4.63669e-313
1.698e-319 6.95503e-316
1.132e-316 4.63669e-313
Which means some where I am multiplying by zeros somewhere in my code. The problem is I cant for the life of me see where. Thanks if there is any help!
Error
If you want to divide by 2*h_x, you need to write this as /(2*h_x), else you divide by 2 and multiply by h_x, giving miniscule values for forces and thus not moving the system by much.
To complement this, you defined the step size in the main program as
double h = 10/1000;
The value on the right is identified as result of an integer division, which is 0. With this step size nothing will change.
Style
Do not construct two data fields for the same value, you would have to ensure that these fields are always synchronized. Use getter methods to present data in a different format.
For science it would be better to use an established vector class that then also provides vector arithmetic, like the one of boost/Eigen.
Use initialization list syntax in the constructor, you do not need an init function to just assign the values.
Verlet
The Verlet method does not work this way. Even if everything goes right coding-wise, the result is a first order method that neither preserves energy nor momentum.
For using Verlet with gravity simulations, see N-Body Gravity Simulation in JavaScript.
The same in a slightly different context, Lennard-Jones potential simulation.
Perhaps also this discussion about general properties of the Verlet method, Velocity verlet algorithm not conserving energy, can be helpful.
The short version is, the stages of the Verlet method are the outer frame. In each stage, all computations have to be carried out for all objects before changing to the next stage. That is, all velocities change, then all positions chance, then all forces are computed and accumulated, then all velocities change with the new forces/accelerations for all objects.
Mixing these steps destroys the order of the method and all conservation properties. (The first two stages can be interleaved, as there is no interaction between objects.)
I implemented some of the suggested changes, using the data of the Pleiades IVP test suite example, as the provided data lead to a rapid explosion of the system.
The main program solarsystem.c with the main Verlet loop
#include <iostream>
#include <cstdio>
#include <vector>
#include "star.h"
using namespace std;
int main()
{
vector<Star> arr = {
Star( 1, 3.0, 3.0, 0.0, 0.0 ),
Star( 2, 3.0,-3.0, 0.0, 0.0 ),
Star( 3,-1.0, 2.0, 0.0, 0.0 ),
Star( 4,-3.0, 0.0, 0.0,-1.25 ),
Star( 5, 2.0, 0.0, 0.0, 1.0 ),
Star( 6,-2.0,-4.0, 1.75, 0.0 ),
Star( 7, 2.0, 4.0,-1.5, 0.0 )
};
int N = arr.size();
double dt = 0.001;
int count = 10;
for ( double time = 0.0; time <= 3.0; time += dt)
{
for ( int inst = 0 ; inst< N; ++inst ) {
arr[inst].Verlet_stage1(dt);
}
for ( int inst = 0 ; inst< N; ++inst ) {
for ( int jnst = inst+1; jnst < N; ++jnst ) {
arr[inst].acceleration(arr[jnst]);
}
}
for ( int inst = 0 ; inst< N; ++inst ) {
arr[inst].Verlet_stage2(dt);
}
if( 10 == count) {
count = 0;
for ( int inst = 0 ; inst< N; ++inst ) {
cout << " " << arr[inst].Position[1] << " " << arr[inst].Position[0];
}
cout << "\n";
}
count++;
}
return 0;
}
and the implementation of the Star class with header
#pragma once
#include <eigen3/Eigen/Dense>
typedef Eigen::Vector2d Vec2D;
const double G = 1;
class Star {
public:
Star( double m, double x_p, double y_p, double x_v, double y_v )
:Mass(m),Position(x_p,y_p),Velocity(x_v,y_v) {};
double Mass;
Vec2D Position, Velocity, Acceleration;
void Verlet_stage1(double dt);
void Verlet_stage2(double dt);
double potential(Star other);
void acceleration(Star &other);
};
and corpus
#include "star.h"
double Star::potential( Star other )
{
Vec2D diff = Position-other.Position;
double R = diff.norm();
return G * Mass * other.Mass / R;
}
void Star::acceleration( Star &other )
{
Vec2D diff = Position-other.Position;
double R = diff.norm();
Vec2D acc = (-G / (R*R*R)) * diff;
Acceleration += other.Mass * acc;
other.Acceleration -= Mass * acc;
}
void Star::Verlet_stage1( double dt )
{
Velocity += (0.5*dt) * Acceleration;
Position += dt*Velocity;
Acceleration *= 0;
}
void Star::Verlet_stage2( double dt )
{
Velocity += (0.5*dt) * Acceleration;
}
This results in the trajectories below. The picture is very depending on the step size dt as near singularities of the potential function, that is, if bodies come very close together, the promise of symplectic methods of near conservation of energy and momentums breaks apart.
I'm personally not against using raw pointers, but complications occur when they don't get managed properly. I have no idea what this code does, more so how it does! Nevertheless, I have tried ameliorating a few errors which I could observe, but evidently this code requires a serious overhaul. I suppose the shortcomings in this code are just due to inexperience, which can be understood.
https://gcc.godbolt.org/z/5zT5o9 Please do keep in mind that this code is still leaking due to usage(non-manage) of raw pointers in various function bodies.
I need to evaluate a double integral where the inner upper Bound is variable:
integral2 between -5 and 5 ( integral1 between 0 and y f(x)dx )dy.
I'm stuck in the calculation of the outer loop which is dependent on the inner loop. My code runs for a really long time but returns zero.
How can i calculate a integral with variable limits?
First I created a function doubleIntegrate. In the first place the function holds the arrays with coefficients for the trapeziodal rule.
double NumericIntegrationDouble::doubleIntegrate(double (*doubleFunc
(const double &x), double dy, const double &innerLowBound, const double
&outerLowBound)
{
double innerValue = 0.0;
double outerValue = 0.0;
// arrays which store function values for the inner (X) and the outer (Y) integration loop
// vector filled with coefficients for the inner poop (trapezoidal rule)
std::vector<double> vecCoeffsX(numberOfIntervalsDouble+1, 2);
vecCoeffsX[0] = 1; // fist coeff = 1
vecCoeffsX[vecCoeffsX.size()-1] = 1; // last coeff = 1
std::vector<double> funcValuesX(numberOfIntervalsDouble+1);
// vector filled with coefficients for the inner poop (trapezoidal rule)
std::vector<double> vecCoeffsY(numberOfIntervalsDouble+1, 2);
vecCoeffsY[0] = 1; // same as above
vecCoeffsY[vecCoeffsY.size()-1] = 1; // same as above
std::vector<double> funcValuesY(numberOfIntervalsDouble+1)
// Then i created a loop in a loop where dy and dy stands for step size of integration. The variables xi and yi stand for the current x and y value.
// outer integration loop dy
for(int i=0; i<=numberOfIntervalsDouble; i++)
{
double yi = outerLowBound + dy*i;
funcValuesY[i] = (*doubleFunc)(yi);
// inner integration loop dx
for(int j=0; j<=numberOfIntervalsDouble; j++)
{
double dx = abs(yi - innerLowBound) / (double)numberOfIntervalsDouble;
double xi = innerLowBound + j*dx;
funcValuesX[j] = (*doubleFunc)(xi);
double multValueX = std::inner_product(vecCoeffsX.begin(), vecCoeffsX.end(), funcValuesX.begin(), 0.0);
double innerValue = 0.5 * dx * multValueX;
suminnerValue = suminnerValue + innerValue;
}
//auto multValueY = std::inner_product(vecCoeffsY.begin(), vecCoeffsY.end(), funcValuesY.begin(), 0.0);
outerValue = 0.5 * dy * suminnerValue;
}
return outerValue;
}
I'm able to make function template parametrized by an other function, however, I don't know how to do it when I want to parametrize it by function with different number of arguments.
See this code:
#include <stdio.h>
#include <math.h>
template < double FUNC( double a ) >
void seq_op( int n, double * as ){
for (int i=0; i<n; i++){ printf( " %f \n", FUNC( as[i] ) ); }
}
template < double FUNC( double a, double b ) >
void seq_op_2( int n, double * as, double * bs ){
for (int i=0; i<n; i++){ printf( " %f \n", FUNC( as[i], bs[i] ) ); }
}
double a_plus_1 ( double a ){ return a + 1.0; }
double a_sq ( double a ){ return a*a; }
double a_plus_b ( double a, double b ){ return a + b; }
double a_times_b( double a, double b ){ return a * b; }
double as[5] = {1,2,3,4};
double bs[5] = {2,2,2,2};
// FUNCTION ====== main
int main(){
printf( "seq_op <a_plus_1> ( 5, as );\n"); seq_op <a_plus_1> ( 4, as );
printf( "seq_op <a_sq> ( 5, as );\n"); seq_op <a_sq> ( 4, as );
printf( "seq_op_2 <a_plus_b> ( 5, as, bs );\n"); seq_op_2 <a_plus_b> ( 4, as, bs );
printf( "seq_op_2 <a_times_b> ( 5, as, bs );\n"); seq_op_2 <a_times_b> ( 4, as, bs );
}
is there a way how to make common template for both cases?
Why I need such silly thing? A more practical example are this two functions which differs only in one line:
#define i3D( ix, iy, iz ) ( iz*nxy + iy*nx + ix )
void getLenardJonesFF( int natom, double * Rs_, double * C6, double * C12 ){
Vec3d * Rs = (Vec3d*) Rs_;
int nx = FF::n.x;
int ny = FF::n.y;
int nz = FF::n.z;
int nxy = ny * nx;
Vec3d rProbe; rProbe.set( 0.0, 0.0, 0.0 ); // we may shift here
for ( int ia=0; ia<nx; ia++ ){
printf( " ia %i \n", ia );
rProbe.add( FF::dCell.a );
for ( int ib=0; ib<ny; ib++ ){
rProbe.add( FF::dCell.b );
for ( int ic=0; ic<nz; ic++ ){
rProbe.add( FF::dCell.c );
Vec3d f; f.set(0.0,0.0,0.0);
for(int iatom=0; iatom<natom; iatom++){
// only this line differs
f.add( forceLJ( Rs[iatom] - rProbe, C6[iatom], C12[iatom] ) );
}
FF::grid[ i3D( ia, ib, ic ) ].add( f );
}
rProbe.add_mul( FF::dCell.c, -nz );
}
rProbe.add_mul( FF::dCell.b, -ny );
}
}
void getCoulombFF( int natom, double * Rs_, double * kQQs ){
Vec3d * Rs = (Vec3d*) Rs_;
int nx = FF::n.x;
int ny = FF::n.y;
int nz = FF::n.z;
int nxy = ny * nx;
Vec3d rProbe; rProbe.set( 0.0, 0.0, 0.0 ); // we may shift here
for ( int ia=0; ia<nx; ia++ ){
printf( " ia %i \n", ia );
rProbe.add( FF::dCell.a );
for ( int ib=0; ib<ny; ib++ ){
rProbe.add( FF::dCell.b );
for ( int ic=0; ic<nz; ic++ ){
rProbe.add( FF::dCell.c );
Vec3d f; f.set(0.0,0.0,0.0);
for(int iatom=0; iatom<natom; iatom++){
// only this line differs
f.add( forceCoulomb( Rs[iatom] - rProbe, kQQs[iatom] );
}
FF::grid[ i3D( ia, ib, ic ) ].add( f );
}
rProbe.add_mul( FF::dCell.c, -nz );
}
rProbe.add_mul( FF::dCell.b, -ny );
}
}
You should be able to combine the two functions using a combination of std::bind() and std::function() (see code on coliru):
#include <stdio.h>
#include <functional>
using namespace std::placeholders;
double getLJForceAtoms (int, int, double*, double*, double*)
{
printf("getLJForceAtoms\n");
return 0;
}
double getCoulombForceAtoms (int, int, double*, double*)
{
printf("getCoulombForceAtoms\n");
return 0;
}
void getFF (int natom, double* Rs_, std::function<double(int, int, double*)> GetForce)
{
int rProbe = 1;
double Force = GetForce(rProbe, natom, Rs_);
}
int main ()
{
double* C6 = nullptr;
double* C12 = nullptr;
double *kQQs = nullptr;
double* Rs_ = nullptr;
auto getLJForceFunc = std::bind(getLJForceAtoms, _1, _2, _3, C6, C12);
auto getCoulombForceFunc = std::bind(getCoulombForceAtoms, _1, _2, _3, kQQs);
getFF(1, Rs_, getLJForceFunc);
getFF(1, Rs_, getCoulombForceFunc);
return 0;
}
which outputs the expected:
getLJForceAtoms
getCoulombForceAtoms
Update -- On Performance
While it is natural to be concerned about performance of using std::function vs templates I would not omit a possible solution without first benchmarking and profiling it.
I can't compare the performance directly as I would need both your complete source code as well as input data set to make accurate benchmarks but I can do a very simple test to show you what it could look like. If I make the force functions do a little work:
double getLJForceAtoms (int x, int y, double* r1, double* r2, double* r3)
{
return cos(log2(abs(sin(log(pow(x, 2) + pow(y, 2))))));
}
and then have a very simple getFF() function call them 10 million times I can get a rough comparison between the various design methods (tests done on VS2013, release build, fast optimization flags):
Direct Call = 1900 ms
Switch = 1900 ms
If (flag) = 1900 ms
Virtual Function = 2400 ms
std::function = 2400 ms
So the std::function method is about 25% slower in this case but the switch and if methods are the same speed as the direct call case. Depending on how much work your actual force functions do you may get worse or better results. These days, the compiler optimizer and the CPU branch predictor are good enough to do a lot of things that may be surprising or even counter-intuitive, which is why actual testing must be done.
I would do a similar benchmark test with your exact code and data set and see what difference, if any, the various designs have. If you really only have two cases as shown in your question then the "if (flag)" method may be a good choice.
I got an error when compile the below code saying that "called object type 'double' is not a function or function pointer". Because 'position' is a 3d vector, so I was trying to access each element of the vector.
int k=1;
int m=1;
double x, y, z;
x=position.x;
y=position.y;
z=position.z;
for (int j = 3; j < 1000 ; j++)
{
x(j) = 2 * x(j-1) - x(j-2) + (delta_t * delta_t * (-1.0*k/m) * x(j-1));
}
You'll actually have to keep track of x(j), x(j-1), and x(j-2) all as separate variables (using the syntax x(j) is akin to calling a function x() with argument j, which is not what you want).
Try:
double xj, xj_m1, xj_m2;
xj_m1 = position.x;
xj_m2 = position.x;
for (int j = 3; j < 1000 ; j++) {
xj = 2 * xj_m1 - xj_m2 + (delta_t * delta_t * (-1.0*k/m) * xj_m1);
//Update xj_m2 and xj_m1 for the next iteration
xj_m2 = xj_m1;
xj_m1 = xj;
}
When you do it:
x=position.x;
You expect that position.x is an array?
To access to an element in a vector, you can use the [] operator:
std::vector<int> myIntVector = { 1, 2, 3 };
int i = myIntVector[0]; // i = 1 because myIntVector[0] is the first element of myIntVector
The variable position looks like a coordinate vector, so it's not an array, it's just a class / struct like this:
struct Vector3
{
double x, y, z;
};
In other words, position.x is just a number.