Here's some code that uses a 4-th degree symplectic integrator:
#include <iostream>
#include <cmath>
struct Vector3 {
double x, y, z;
};
Vector3 operator+(Vector3 const &v1, Vector3 const &v2) {
return Vector3{v1.x + v2.x, v1.y + v2.y, v1.z + v2.z};
}
Vector3 &operator+=(Vector3 &v1, Vector3 const &v2) {
v1.x += v2.x;
v1.y += v2.y;
v1.z += v2.z;
return v1;
}
Vector3 operator-(Vector3 const &v1, Vector3 const &v2) {
return Vector3{v1.x - v2.x, v1.y - v2.y, v1.z - v2.z};
}
Vector3 operator*(double scalar, Vector3 const &v) {
return Vector3{scalar * v.x, scalar * v.y, scalar * v.z};
}
Vector3 operator*(Vector3 const &v, double scalar) {
return scalar * v;
}
double length(Vector3 const &v) {
return std::sqrt(v.x * v.x + v.y * v.y + v.z * v.z);
}
std::ostream &operator<<(std::ostream &os, Vector3 const &v) {
return os << '(' << v.x << ',' << v.y << ',' << v.z << ')';
}
// Taken from Wikipedia's example of a 4th-order symplectic integrator
void SI_order4(Vector3 &x, Vector3 &v, Vector3 (*Acceleration)(Vector3 const &), double delta_t) {
double const cr2 = std::pow(2.0, 1.0/3.0);
double const c[4] = {
1.0/(2.0*(2.0-cr2)),
(1.0-cr2)/(2.0*(2.0-cr2)),
(1.0-cr2)/(2.0*(2.0-cr2)),
1.0/(2.0*(2.0-cr2))
};
double const d[4] = {
1.0/(2.0-cr2),
-cr2/(2.0-cr2),
1.0/(2.0-cr2),
0.0
};
for (int s = 0; s < 4; ++s) {
x += c[s] * delta_t * v;
v += d[s] * delta_t * Acceleration(x);
}
}
double const gravitational_constant = 1.0;
double const sun_mass = 1.0;
Vector3 const mercury_initial_position{0.0, 1.0, 0.0};
Vector3 const mercury_initial_velocity{1.0, 0.0, 0.0};
double const delta_t = 0.02;
Vector3 gravitational_acceleration(Vector3 const &x) {
return - gravitational_constant * sun_mass / std::pow(length(x), 3) * x;
}
int main() {
Vector3 x = mercury_initial_position;
Vector3 v = mercury_initial_velocity;
for (int i = 0; i < 158; ++i) {
std::cout << "x=" << x << " v=" << v << " (distance=" << length(x) << ", speed=" << length(v) << ")\n";
SI_order4(x, v, gravitational_acceleration, delta_t);
}
}
Enjoy!