[ create a new paste ] login | about

Link: http://codepad.org/AdRSm2wP    [ raw code | fork ]

D, pasted on Nov 25:
/* The Great Computer Language Shootout
   http://shootout.alioth.debian.org/
   compile: dmd -O -inline -release nbody.d
*/

import core.stdc.stdio, std.conv, std.math, std.typetuple;

template Iota(int start, int stop) {
    static if (stop <= start)
        alias TypeTuple!() Iota;
    else
        alias TypeTuple!(Iota!(start, stop-1), stop-1) Iota;
}


struct BodySystem {
    alias immutable(double) imd;
    private:
        enum double SOLAR_MASS = 4 * PI ^^ 2;
        enum double DAYS_PER_YEAR = 365.24;

        static struct Body {
            double x, y, z, vx, vy, vz;
            imd mass;

            void offsetMomentum(in double px, in double py, in double pz) pure nothrow {
                vx = -px / SOLAR_MASS;
                vy = -py / SOLAR_MASS;
                vz = -pz / SOLAR_MASS;
            }
        }

        auto bodies = TypeTuple!(
            Body(0,0,0, 0,0,0, SOLAR_MASS),

            Body( 4.84143144246472090e+00,
                 -1.16032004402742839e+00,
                 -1.03622044471123109e-01,
                  1.66007664274403694e-03 * DAYS_PER_YEAR,
                  7.69901118419740425e-03 * DAYS_PER_YEAR,
                 -6.90460016972063023e-05 * DAYS_PER_YEAR,
                  9.54791938424326609e-04 * SOLAR_MASS),

            Body( 8.34336671824457987e+00,
                  4.12479856412430479e+00,
                 -4.03523417114321381e-01,
                 -2.76742510726862411e-03 * DAYS_PER_YEAR,
                  4.99852801234917238e-03 * DAYS_PER_YEAR,
                  2.30417297573763929e-05 * DAYS_PER_YEAR,
                  2.85885980666130812e-04 * SOLAR_MASS),

            Body( 1.28943695621391310e+01,
                 -1.51111514016986312e+01,
                 -2.23307578892655734e-01,
                  2.96460137564761618e-03 * DAYS_PER_YEAR,
                  2.37847173959480950e-03 * DAYS_PER_YEAR,
                 -2.96589568540237556e-05 * DAYS_PER_YEAR,
                  4.36624404335156298e-05 * SOLAR_MASS),

            Body( 1.53796971148509165e+01,
                 -2.59193146099879641e+01,
                  1.79258772950371181e-01,
                  2.68067772490389322e-03 * DAYS_PER_YEAR,
                  1.62824170038242295e-03 * DAYS_PER_YEAR,
                 -9.51592254519715870e-05 * DAYS_PER_YEAR,
                  5.15138902046611451e-05 * SOLAR_MASS));

            enum int NB = bodies.length;

    public:
        void offset() pure nothrow {
            double px = 0.0, py = 0.0, pz = 0.0;

            foreach (const(Body) b; bodies) {
                px += b.vx * b.mass;
                py += b.vy * b.mass;
                pz += b.vz * b.mass;
            }

            bodies[0].offsetMomentum(px, py, pz);
        }


        double energy() const pure nothrow {
            double e = 0.0;

            foreach (i, b1; bodies) {
                imd im = b1.mass;
                e += 0.5 * im * (b1.vx ^^ 2 + b1.vy ^^ 2 + b1.vz ^^ 2);

                foreach (b2; bodies[i + 1 .. $]) {
                    imd dx = b1.x - b2.x;
                    imd dy = b1.y - b2.y;
                    imd dz = b1.z - b2.z;

                    e -= (im * b2.mass) / sqrt(dx ^^ 2 + dy ^^ 2 + dz ^^ 2);
                }
            }

            return e;
        }


        void advance(double dt)() pure nothrow {
            foreach (i; Iota!(0, NB))
                foreach (j; Iota!(i + 1, NB)) {
                    enum double im = bodies[i].mass;
                    enum double jm = bodies[j].mass;

                    imd dx = bodies[i].x - bodies[j].x;
                    imd dy = bodies[i].y - bodies[j].y;
                    imd dz = bodies[i].z - bodies[j].z;

                    imd dSquared = dx ^^ 2 + dy ^^ 2 + dz ^^ 2;
                    imd mag = dt / (dSquared * sqrt(dSquared));

                    bodies[i].vx -= dx * jm * mag;
                    bodies[i].vy -= dy * jm * mag;
                    bodies[i].vz -= dz * jm * mag;

                    bodies[j].vx += dx * im * mag;
                    bodies[j].vy += dy * im * mag;
                    bodies[j].vz += dz * im * mag;
                }

            foreach (i; Iota!(0, NB))
                with (bodies[i]) {
                    x += dt * vx;
                    y += dt * vy;
                    z += dt * vz;
                }
        }
}


void main(string[] args) {
    immutable int n = args.length > 1 ? to!int(args[1]) : 100;

    BodySystem bodies;
    bodies.offset();
    printf("%0.9f\n", bodies.energy());

    foreach (i; 0 .. n)
        bodies.advance!(0.01)();

    printf("%0.9f\n", bodies.energy());
}


Create a new paste based on this one


Comments: