Есть ли способ повторить это, чтобы мне не нужно было добавлять каждую функцию?

#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 — это двоичный оператор с аккумулятором в качестве первого аргумента, а не проекция.