Esempio n. 1
0
        public static void Investigations()
        {
            double geosyncOrbitR = 42000.0;               // Real example, approximate geosynchronous orbit in km
            double oneMillimeter = 1.0 / 1000.0 / 1000.0; // One mm in kilometers

            Console.WriteLine("=========== Geosync Orbit plus 1/3 millimeter (and smaller) in kilometers ==========");
            Console.WriteLine("   Objective is to have fractions of a millimeter correctly accumulate over many additions\n");
            double large = geosyncOrbitR;
            double small = oneMillimeter / 3.0;

            Console.WriteLine("large: {0}, log10(large): {1:G5}\n", large, Math.Log10(Math.Abs(large)));

            for (int i = 0; i < 200; i++)
            {
                Console.WriteLine("large + small ({0,22:G17}) = {1,22:G17} - sig digits in calc: {2}, log10(small): {3,7:G5}, logs difference: {4,6:G5} ({5}) (CAP V2: {6}, V3: {7})",
                                  small, large + small, DecimalAdditionPrecision(large, small), Math.Log10(Math.Abs(small)),
                                  Math.Log10(Math.Abs(large)) - Math.Log10(Math.Abs(small)), FloatingPointUtil.AdditionMagnitudeDifference(large, small),
                                  FloatingPointUtil.CheckAdditionPrecisionV2(large, small), FloatingPointUtil.CheckAdditionPrecisionV3(large, small));
                if (large + small == large)
                {
                    break;
                }
                small *= 0.1;
            }
        }
Esempio n. 2
0
        public void MoveWithPrecisionCheck(SimPoint accel, double deltaT)
        {
            if (!((accel.X == 0.0) && (accel.Y == 0.0)))
            {
                // Apply linear acceleration during the time interval

                double deltaVX = accel.X * deltaT;
                if (FloatingPointUtil.CheckAdditionPrecision(velocity.X, deltaVX))
                {
                    DisplayPrecisionIssue(velocity.X, deltaVX, "Adding DeltaV to VX", bodyNumber);
                }
                double newVelocityX = velocity.X + deltaVX;

                double deltaPX = (velocity.X + newVelocityX) / 2 * deltaT;
                if (FloatingPointUtil.CheckAdditionPrecision(position.X, deltaPX))
                {
                    DisplayPrecisionIssue(position.X, deltaPX, "Adding to Position.X", bodyNumber);
                }
                position.X += deltaPX;

                velocity.X = newVelocityX;


                double deltaVY = accel.Y * deltaT;
                if (FloatingPointUtil.CheckAdditionPrecision(velocity.Y, deltaVY))
                {
                    DisplayPrecisionIssue(velocity.Y, deltaVY, "Adding DeltaV to VY", bodyNumber);
                }
                double newVelocityY = velocity.Y + deltaVY;

                double deltaPY = (velocity.Y + newVelocityY) / 2 * deltaT;
                if (FloatingPointUtil.CheckAdditionPrecision(position.Y, deltaPY))
                {
                    DisplayPrecisionIssue(position.Y, deltaPY, "Adding to Position.Y", bodyNumber);
                }
                position.Y += deltaPY;

                velocity.Y = newVelocityY;
            }
        }
Esempio n. 3
0
        public static void CAP_SpecificExample()
        {
            // Run and display calculation described by this comment from CheckAdditionPrecision():
            // Specific example:
            //  This limit allows any quantity around or above 1/100 of a millimeter to be repeatedly added to 42,000 km (geosync orbit radius)
            //  without losing too much accuracy. E.g. 1/300 of a mm added 10,000 times should about equal 1/30 of a meter

            double geosyncOrbitR = 42000.0;               // Real example, approximate geosynchronous orbit in km
            double oneMillimeter = 1.0 / 1000.0 / 1000.0; // One mm in kilometers

            double smallDelta   = oneMillimeter / 300.0;
            int    numAdditions = 10000;

            Console.WriteLine("Large value = {0:N0}, small value = {1:G17}, addition iterations = {2:N0}", geosyncOrbitR, smallDelta, numAdditions);
            Console.WriteLine("CheckAdditionPrecision({0:N0}, {1}) = {2}", geosyncOrbitR, smallDelta, FloatingPointUtil.CheckAdditionPrecision(geosyncOrbitR, smallDelta));

            for (int i = 0; i < numAdditions; i++)
            {
                geosyncOrbitR += smallDelta;
            }

            Console.WriteLine("Result = {0:G17}", geosyncOrbitR);
        }
Esempio n. 4
0
    public static void RunTest(long iterations)
    {
        Stopwatch stopwatch = new Stopwatch();

        long loopTime, randomGenerationTime, additionTime, checkPrecisionTimeV1, checkPrecisionTimeV2, checkPrecisionTimeV3;

        stopwatch.Start();
        for (long i = 0; i < iterations;)
        {
            i++;
        }
        loopTime = stopwatch.ElapsedMilliseconds;

        Double[] randomA = new Double[iterations];
        Double[] randomB = new Double[iterations];
        Random   random  = new Random();

        stopwatch.Reset(); stopwatch.Start();
        for (long i = 0; i < iterations; i++)
        {
            randomA[i] = random.NextDouble();
            randomB[i] = random.NextDouble();
        }
        randomGenerationTime = stopwatch.ElapsedMilliseconds;

        double sum;

        stopwatch.Reset(); stopwatch.Start();
        for (long i = 0; i < iterations; i++)
        {
            sum = randomA[i] + randomB[i];
        }
        additionTime = stopwatch.ElapsedMilliseconds;

        bool result;

        stopwatch.Reset(); stopwatch.Start();
        for (long i = 0; i < iterations; i++)
        {
            result = FloatingPointUtil.CheckAdditionPrecisionV1(randomA[i], randomB[i]);
        }
        checkPrecisionTimeV1 = stopwatch.ElapsedMilliseconds;


        stopwatch.Reset(); stopwatch.Start();
        for (long i = 0; i < iterations; i++)
        {
            result = FloatingPointUtil.CheckAdditionPrecisionV2(randomA[i], randomB[i]);
        }
        checkPrecisionTimeV2 = stopwatch.ElapsedMilliseconds;

        stopwatch.Reset(); stopwatch.Start();
        for (long i = 0; i < iterations; i++)
        {
            result = FloatingPointUtil.CheckAdditionPrecisionV3(randomA[i], randomB[i]);
        }
        checkPrecisionTimeV3 = stopwatch.ElapsedMilliseconds;


        Console.WriteLine("Performance Test of CheckAdditionPrecision() - running {0:N0} iterations", iterations);
        Console.WriteLine("Times in ms:");
        Console.WriteLine("   Empty loop: {0:N0}", loopTime);
        Console.WriteLine("   Random number generation: {0:N0}, net: {1:N0}", randomGenerationTime, randomGenerationTime - loopTime);
        Console.WriteLine("   Addition: {0:N0}, net: {1:N0}", additionTime, additionTime - loopTime);
        Console.WriteLine("   CAP V1():   {0:N0}, net: {1:N0}", checkPrecisionTimeV1, checkPrecisionTimeV1 - loopTime);
        Console.WriteLine("   CAP V2():   {0:N0}, net: {1:N0}", checkPrecisionTimeV2, checkPrecisionTimeV2 - loopTime);
        Console.WriteLine("   CAP V3():   {0:N0}, net: {1:N0}", checkPrecisionTimeV3, checkPrecisionTimeV3 - loopTime);
        Console.WriteLine("CheckAdditionPrecisionV3() takes {0:N2} times longer than addition", (checkPrecisionTimeV3 - loopTime) / (additionTime - loopTime));
        Console.WriteLine("CheckAdditionPrecisionV3() runs in {0:N2}% time of original version",
                          ((float)(checkPrecisionTimeV3 - loopTime) / (float)(checkPrecisionTimeV1 - loopTime)) * 100.0f);
    }
Esempio n. 5
0
        //  simRunning - true if sim is auto-running
        //               false if sim is single stepping
        public void Step(double timeInterval, bool simRunning)
        {
            Stopwatch perfStopwatch     = new Stopwatch();
            long      perfIntervalTicks = 0L;
            bool      simStepping       = !simRunning;

            double scaledTimeInterval = timeInterval * SpeedFactor;

            SetTimeForTrailMark(simElapsedTime);

            if (simStepping)
            {
                Debug.WriteLine("Elapsed times for {0} bodies:", bodies.Count());
                perfStopwatch.Start();
            }

            if (accelerations == null)
            {
                accelerations = new SimPoint[bodies.Count()];
            }

            if (checkSim)
            {
                if (positions == null)
                {
                    positions = new SimPoint[bodies.Count()];
                }
                if (velocities == null)
                {
                    velocities = new SimPoint[bodies.Count()];
                }
            }

            double timeIntervalPerCycle = scaledTimeInterval / (double)simCalcSettings.CalculationCyclesPerFrame;

            List <SimPoint> otherPositions     = new List <SimPoint>();
            List <SimPoint> otherAccelerations = new List <SimPoint>();

            if (checkSim)
            {
                for (int i = 0; i < bodies.Count(); i++)
                {
                    positions[i]  = bodies[i].Position;
                    velocities[i] = bodies[i].Velocity;
                }
                Validate5BodyCross(positions, "Positions Before Update");
                Validate5BodyCross(velocities, "Velocities Before Update");
            }

            for (int calcCycle = 0; calcCycle < simCalcSettings.CalculationCyclesPerFrame; calcCycle++)
            {
                // Calculate NBody acceleration
                if (simCalcSettings.CheckAllAdditionPrecision)
                {
                    for (int i = 0; i < bodies.Count(); i++)
                    {
                        accelerations[i].X = 0.0;
                        accelerations[i].Y = 0.0;

                        for (int j = 0; j < bodies.Count(); j++)
                        {
                            if ((i != j) && bodies[j].IsGravitySource)
                            {
                                SimPoint accel = bodies[i].BodyToBodyAccelerate(bodies[j]);
                                if (simRounding > 0)
                                {
                                    accel.X += Math.Round(accel.X, simRounding, MidpointRounding.AwayFromZero);
                                    accel.Y += Math.Round(accel.Y, simRounding, MidpointRounding.AwayFromZero);
                                }
                                if (FloatingPointUtil.CheckAdditionPrecision(accelerations[i].X, accel.X))
                                {
                                    Body.DisplayPrecisionIssue(accelerations[i].X, accel.X, "Accumulating Accel.X", i);
                                }
                                accelerations[i].X += accel.X;
                                if (FloatingPointUtil.CheckAdditionPrecision(accelerations[i].Y, accel.Y))
                                {
                                    Body.DisplayPrecisionIssue(accelerations[i].Y, accel.Y, "Accumulating Accel.Y", i);
                                }
                                accelerations[i].Y += accel.Y;
                            }
                        }
                    }
                }
                else if (simRounding > 0)
                {
                    for (int i = 0; i < bodies.Count(); i++)
                    {
                        accelerations[i].X = 0.0;
                        accelerations[i].Y = 0.0;

                        for (int j = 0; j < bodies.Count(); j++)
                        {
                            if ((i != j) && bodies[j].IsGravitySource)
                            {
                                SimPoint accel = bodies[i].BodyToBodyAccelerate(bodies[j]);
                                accelerations[i].X += Math.Round(accel.X, simRounding, MidpointRounding.AwayFromZero);
                                accelerations[i].Y += Math.Round(accel.Y, simRounding, MidpointRounding.AwayFromZero);
                            }
                        }
                    }
                }
                else
                {
                    for (int i = 0; i < bodies.Count(); i++)
                    {
                        accelerations[i].X = 0.0;
                        accelerations[i].Y = 0.0;

                        for (int j = 0; j < bodies.Count(); j++)
                        {
                            if ((i != j) && bodies[j].IsGravitySource)
                            {
                                SimPoint accel = bodies[i].BodyToBodyAccelerate(bodies[j]);
                                accelerations[i].X += accel.X;
                                accelerations[i].Y += accel.Y;
                            }
                        }
                    }
                }

                //if (checkSim) Validate5BodyCross(accelerations, "Accelerations Before Limit and Rounding");

                if (accelerationLimitOn)
                {
                    EnforceAccelerationLimit(accelerations, accelerationLimit);
                }

                if (simRounding > 0)
                {
                    RoundAccelerations(accelerations, simRounding);
                }

                if (checkSim)
                {
                    Validate5BodyCross(accelerations, "Accelerations After Limit and Rounding");
                }

                // Update positons and velocities
                if (simCalcSettings.CheckAllAdditionPrecision)
                {
                    for (int i = 0; i < bodies.Count(); i++)
                    {
                        bodies[i].MoveWithPrecisionCheck(accelerations[i], timeIntervalPerCycle);
                    }
                }
                else
                {
                    for (int i = 0; i < bodies.Count(); i++)
                    {
                        bodies[i].Move(accelerations[i], timeIntervalPerCycle);
                    }
                }

                if (checkSim)
                {
                    for (int i = 0; i < bodies.Count(); i++)
                    {
                        positions[i]  = bodies[i].Position;
                        velocities[i] = bodies[i].Velocity;
                    }
                    Validate5BodyCross(positions, "Positions After Update");
                    Validate5BodyCross(velocities, "Velocities After Update");
                }

                simElapsedTime += timeIntervalPerCycle;

                if ((MainPage.trailsEnabled) && TimeForTrailsMark(simElapsedTime))
                {
                    DrawTrails();
                }
            }
            if (simStepping)
            {
                perfIntervalTicks = DisplayPerfIntervalElapsed(perfStopwatch, perfIntervalTicks,
                                                               String.Format("Compute N-body accelerations, update positions & velocities ({0} iterations)", simCalcSettings.CalculationCyclesPerFrame));
            }


            // Update rendering
            renderer.BodiesMoved(bodies);
            simPage.UpdateMonitoredValues(bodies[monitoredBody], simElapsedTime);

            if (simStepping)
            {
                perfIntervalTicks = DisplayPerfIntervalElapsed(perfStopwatch, perfIntervalTicks, "Update transforms of XAML shapes & monitored values");
            }

            if (simStepping)
            {
                Debug.WriteLine("Total elapsed time = {0:F2} ms", (double)perfIntervalTicks / (double)(Stopwatch.Frequency / 1000L));
                Debug.WriteLine("");
            }

            // stepRunning = false;
        }
Esempio n. 6
0
 public static void DisplayPrecisionIssue(double a, double b, string whichCalculation, int bodyNumber)
 {
     if (debugMessageCount++ < DebugMessageCountLimit)
     {
         Debug.WriteLine("Body #{4} {3}: a = {0:G17}, b = {1:G17}, mag diff = {2}", a, b, FloatingPointUtil.AdditionMagnitudeDifference(a, b), whichCalculation, bodyNumber);
     }
     if (debugMessageCount == DebugMessageCountLimit)
     {
         Debug.WriteLine(">>> Reached limit of {0:N0} precision warning messages. No more will be displayed.", DebugMessageCountLimit);
     }
 }