PDA

Visualizza la versione completa : [C++] Puntatori a funzione per flessibilità programmi di fisica computazionale


RooccoXXI
09-08-2012, 23:52
Ciao a tutti.
Sto cercando di capire come utilizzare dei puntatori a funzione, che mi servirebbero per rendere flessibili alcuni programmi di fisica computazionale che sto scrivendo. Ho letto un po' in internet e questo é il programma che ho creato (integrazione numerica con lo schema di Euler di una palla da baseball con e senza attrito dell'aria):

#include <iostream>
using std::cout;
using std::endl;

#include <array>
using std::array;

#include <utility>
using std::move;

#include <initializer_list>
using std::initializer_list;

#include <cmath>
using std::sqrt;
using std::sin;
using std::cos;

void euler(
double dt,
array<double,2>& r_old,
array<double,2>& v_old,
array<double,2> (*f)(array<double,2>, array<double,2>))
{
array<double,2> r_new{{r_old[0] + dt * v_old[0], r_old[0] + dt * v_old[0]}};
array<double,2> v_new{{v_old[0] + dt * f(r_old,v_old)[0], v_old[0] + dt * f(r_old,v_old)[0]}};

r_old = r_new;
v_old = v_new;
}

array<double,2> accel(array<double,2> x, array<double,2> v)
{
array<double,2> a{{0,-9.81}};

return std::move(a);
}

array<double,2> accel_air(array<double,2> x, array<double,2> v)
{
double air_cst(-0.5*0.35*1.2*4.3e-3/0.145);
double norm(sqrt(v[0]*v[0] + v[1]*v[1]));

array<double,2> a{{air_cst * norm * v[0], air_cst * norm * v[1] - 9.81}};
}

int main()
{
double speed(50.);
double angle(45.);
double tau(0.1);
double h_init(1.);

array<double,2> r{{0.,h_init}};
array<double,2> v{{speed*cos(angle*M_PI/180), speed*sin(angle*M_PI/180)}};

do
{
cout << r[0] << ' ' << r[1] << endl;

euler(tau, r, v, accel(r,v));
}
while(r[1] > 0);

cout << endl;

do
{
cout << r[0] << ' ' << r[1] << endl;

euler(tau, r, v, accel_air(r,v));
}
while(r[1] > 0);

return 0;
}

Comilando con g++-4.7 ottengo però gli errori seguenti, che proprio non riesco a capire:

g++-mp-4.7 -std=c++11 Baseball.cpp -o Baseball
Baseball.cpp: In function 'int main()':
Baseball.cpp:61:30: error: cannot convert 'std::array<double, 2ul>' to 'std::array<double, 2ul> (*)(std::array<double, 2ul>, std::array<double, 2ul>)' for argument '4' to 'void euler(double, std::array<double, 2ul>&, std::array<double, 2ul>&, std::array<double, 2ul> (*)(std::array<double, 2ul>, std::array<double, 2ul>))'
Baseball.cpp:71:34: error: cannot convert 'std::array<double, 2ul>' to 'std::array<double, 2ul> (*)(std::array<double, 2ul>, std::array<double, 2ul>)' for argument '4' to 'void euler(double, std::array<double, 2ul>&, std::array<double, 2ul>&, std::array<double, 2ul> (*)(std::array<double, 2ul>, std::array<double, 2ul>))'

Grazie.

XAlbeX
10-08-2012, 00:17
quello che intende dire è:


Originariamente inviato da g++
La funzione euler ha come quarto parametro un puntatore a funzione, mentre quello che ritorna da accel o accel_air è un array<double,2>. E' impossibile eseguire un cast e quindi non ho intenzione di continuare a compilare.
:D


Quando scrivi

euler(tau, r, v, accel(r,v));
accel viene eseguita e il suo valore di ritorno viene passato a euler.. nessun puntantore a funzione viene passato.
Dovresti scrivere

euler(tau, r, v, accel);

RooccoXXI
10-08-2012, 11:30
Originariamente inviato da XAlbeX
quello che intende dire è:


:D


Quando scrivi

euler(tau, r, v, accel(r,v));
accel viene eseguita e il suo valore di ritorno viene passato a euler.. nessun puntantore a funzione viene passato.
Dovresti scrivere

euler(tau, r, v, accel);

Grazie mille. Che stupido che sono. Quindi il nome di una funzione lo posso considerare come un puntatore alla porzione di codice da eseguire (o qualcosa del genere)?

Ora compila, ma gli oggetti partono per la tangente, cioè volano in linea retta e non capisco perché... Qualche idea?


#include <iostream>
using std::cout;
using std::endl;

#include <array>
using std::array;

#include <utility>
using std::move;

#include <initializer_list>
using std::initializer_list;

#include <cmath>
using std::sqrt;
using std::sin;
using std::cos;

void euler(
double dt,
array<double,2>& r_old,
array<double,2>& v_old,
array<double,2> (*f)(array<double,2>, array<double,2>))
{
array<double,2> r_new{{r_old[0] + dt * v_old[0], r_old[0] + dt * v_old[0]}};
array<double,2> v_new{{v_old[0] + dt * f(r_old,v_old)[0], v_old[0] + dt * f(r_old,v_old)[0]}};

r_old = r_new;
v_old = v_new;
}

array<double,2> accel(array<double,2> x, array<double,2> v)
{
array<double,2> a{{0,-9.81}};

return std::move(a);
}

array<double,2> accel_air(array<double,2> x, array<double,2> v)
{
double air_cst(-0.5*0.35*1.2*4.3e-3/0.145);
double norm(sqrt(v[0]*v[0] + v[1]*v[1]));

array<double,2> a{{air_cst * norm * v[0], air_cst * norm * v[1] - 9.81}};

return std::move(a);
}

int main()
{
double speed(50.);
double angle(45.);
double tau(0.1);
double h_init(1.);

array<double,2> r{{0.,h_init}};
array<double,2> v{{speed*cos(angle*M_PI/180), speed*sin(angle*M_PI/180)}};

do
{
cout << r[0] << ' ' << r[1] << endl;

euler(tau, r, v, accel);
}
while(r[1] > 0);

cout << endl;

array<double,2> r_air{{0.,h_init}};
array<double,2> v_air{{speed*cos(angle*M_PI/180), speed*sin(angle*M_PI/180)}};

do
{
cout << r[0] << ' ' << r[1] << endl;

euler(tau, r_air, v_air, accel_air);
}
while(r_air[1] > 0);

return 0;
}

XAlbeX
10-08-2012, 13:16
array<double,2> r_new{{r_old[0] + dt * v_old[0], r_old[0] + dt * v_old[0]}};
array<double,2> v_new{{v_old[0] + dt * f(r_old,v_old)[0], v_old[0] + dt * f(r_old,v_old)[0]}};
dovrebbe essere

array<double,2> r_new{{r_old[0] + dt * v_old[0], r_old[1] + dt * v_old[1]}};
array<double,2> v_new{{v_old[0] + dt * f(r_old,v_old)[0], v_old[1] + dt * f(r_old,v_old)[1]}};
perché calcoli due volte f(r_old,v_old)?
controlla se ora funziona

RooccoXXI
10-08-2012, 13:34
Originariamente inviato da XAlbeX

array<double,2> r_new{{r_old[0] + dt * v_old[0], r_old[0] + dt * v_old[0]}};
array<double,2> v_new{{v_old[0] + dt * f(r_old,v_old)[0], v_old[0] + dt * f(r_old,v_old)[0]}};
dovrebbe essere

array<double,2> r_new{{r_old[0] + dt * v_old[0], r_old[1] + dt * v_old[1]}};
array<double,2> v_new{{v_old[0] + dt * f(r_old,v_old)[0], v_old[1] + dt * f(r_old,v_old)[1]}};
perché calcoli due volte f(r_old,v_old)?
controlla se ora funziona

:dhò: :dhò: :dhò:

Che stupido! Grazie mille!

Loading