Jason
Jason

Reputation: 13

Is there a way to iterate this so I don't have to add every each function?

Is there a way to iterate this so I don't have to add every each function? Lets say I have 4 planets and I want to add every gforcex to planet[1].forcex. (this is from an n-body simulation project)

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);

Upvotes: 1

Views: 101

Answers (2)

JohnFilleau
JohnFilleau

Reputation: 4288

This is a great spot for 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 (auto& p : planet) {
        p.forcex = std::accumulate(
            std::begin(planet),
            std::end(planet),
            force_t(0),
            [&](const force_t& force, const Planet& other) {
                if (&p == &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";
    }
}

This assumes that your planet container is full of objects of type Planet.

You'll have to #include <numeric> for std::accumulate and you'll need #include <iterator> for std::begin and std::end, depending on what type planet is. If planet is a standard container std::vector<Planet> or std::array<Planet, N>, then planet.begin() and planet.end() work as well.

I recommend calling planet planets, since that's more accurate.

I recommend changing your gforcex function signature to force_t gforcex(const Planet& a, const Planet& b);

I recommend using a standard library container for planet(s) (probably std::vector<Planet>, but std::array<Planet, N> would be fine too) instead of an array if you're currently using an array.

Upvotes: 1

cigien
cigien

Reputation: 60308

Here's a simple solution:

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);

Upvotes: 2

Related Questions