#c #function #loops #for-loop
#c #функция #циклы #для цикла
Вопрос:
Есть ли способ повторить это, чтобы мне не нужно было добавлять каждую функцию? Допустим, у меня есть 4 планеты, и я хочу добавить каждый gforcex в planet[1].forcex. (это из проекта моделирования n-body)
planet[1].forcex =
gforcex(planet[1].posx, planet[1].posy, planet[2].posx, planet[2].posy)
gforcex(planet[1].posx, planet[1].posy, planet[3].posx, planet[3].posy)
gforcex(planet[1].posx, planet[1].posy, planet[4].posx, planet[4].posy);
Комментарии:
1.
auto g = [amp;](size_t a, size_t b) { return gforcex(planet[a].posx, planet[a].posy, planet[b].posx, planet[b].posy); };
итак, вы можете сделатьplanet[1].forcex = g(1,2) g(1,3) g(1,4);
или иметь цикл for, чтобы сделать это за вас.2. Предполагая, что fhat
gforcex()
не принимает аргументы по ссылке или (если это так) не изменяет их значение, тогдаplanet[1].forcex = 0; for (i = 2; i < 5; i) planet[1].forcex = gforcex(planet[1].posx, planet[1].posy, planet[i].posx, planet[i].posy);
будет работать.
Ответ №1:
Вот простое решение:
planet[1].forcex = 0;
for (int i : {2, 3, 4})
planet[1].forcex =
gforcex(planet[1].posx, planet[1].posy, planet[i].posx, planet[i].posy);
Ответ №2:
Это отличное место для std::accumulate
.
#include <cmath>
#include <iostream>
#include <iterator>
#include <numeric>
using position_t = double;
using force_t = double;
class Planet {
public:
Planet(position_t x, position_t y)
: posx(x)
, posy(y)
, forcex(0)
{}
position_t posx;
position_t posy;
force_t forcex;
};
force_t gforcex(position_t a_x, position_t a_y, position_t b_x, position_t b_y) {
return 1.0 / std::sqrt(std::pow(a_x - b_x, 2) std::pow(a_y - b_y, 2));
}
int main() {
Planet planet[] = {
{1, 2},
{3, 4},
{-1, -2},
{-3, -4}
};
for (autoamp; p : planet) {
p.forcex = std::accumulate(
std::begin(planet),
std::end(planet),
force_t(0),
[amp;](const force_tamp; force, const Planetamp; other) {
if (amp;p == amp;other) return force;
else return force gforcex(p.posx, p.posy, other.posx, other.posy);
}
);
}
for (int i = 0; i < sizeof(planet)/sizeof(planet[0]); i) {
std::cout << "Planet " << i << " forcex: " << planet[i].forcex << "n";
}
}
Это предполагает, что ваш planet
контейнер заполнен объектами типа Planet
.
Вам нужно будет #include <numeric>
для std::accumulate
и вам понадобится #include <iterator>
для std::begin
и std::end
, в зависимости от того, какой тип planet
. Если planet
это стандартный контейнер std::vector<Planet>
или std::array<Planet, N>
, то planet.begin()
и planet.end()
также работают.
Я рекомендую вызывать planet
planets
, так как это более точно.
Я рекомендую изменить gforcex
подпись вашей функции на force_t gforcex(const Planetamp; a, const Planetamp; b);
Я рекомендую использовать стандартный библиотечный контейнер для planet
( s
) (возможно std::vector<Planet>
, но std::array<Planet, N>
тоже подойдет) вместо массива, если вы в настоящее время используете массив.
Комментарии:
1. В вашем примере вы также добавляете gforcex планеты с самим собой, что, вероятно, расходится.
2. @GiovanniCerretani спасибо. Добавлена проверка на равенство адресов. Мое первоначальное предположение заключалось в том, что distance == 0 подразумевает g == 0, что в ретроспективе звучит неправильно. Я еще не допил свою первую чашку субботнего кофе.
3. Предикат
std::accumulate
— это двоичный оператор с аккумулятором в качестве первого аргумента, а не проекция.