Reputation: 256
Take a hypothetical Aircraft class that has two properties; Altitude and AltitudeChange:
public class Aircraft
{
public double Altitude { get; set; }
public AltitudeChange { get; set; }
}
And Altitude change has two properties; Altitude and RateOfClimb:
public class AltitudeChange
{
public double Altitude { get; set; }
public double RateOfClimb { get; set; } //Negative for descent
}
If we have a 'Worker Thread' that updates the Aircraft's altitude based on the time ellapsed and the Rate of Climb, what's the ideal design/implementation to ensure the loop stops when the new Altitude is hit?
private void AltitudeThreadWork()
{
var updated = DateTime.Now;
while (Aircraft.Altitude != AltitudeChange.Altitude)
{
UpdateAltitude((DateTime.Now - updated).TotalMilliseconds);
updated = DateTime.Now;
Thread.Sleep(40);
}
}
private void UpdateAltitude(double ellapsed)
{
Aircraft.Altitude += ellapsed*(AltitudeChange.RateOfClimb/60000d);
}
For example, this thread does't stop the climbing process because the double precision numbers are often not going to exactly equal each other.
Even if you cast the double to an int, you still can't be 100% sure that the two values will equal.
Upvotes: 1
Views: 120
Reputation: 13022
private void AltitudeThreadWork()
{
var updated = DateTime.Now;
bool above = Aircraft.Altitude > AltitudeChange.Altitude; // Determine if it is a climbing or a descent
while ((Aircraft.Altitude > AltitudeChange.Altitude) == above) // Check if it is in the same side of the plane defined by Altitude
// (because altitude is a continuous function, if it is on the other "side" it means it has crossed the given altitude)
{
UpdateAltitude((DateTime.Now - updated).TotalMilliseconds);
updated = DateTime.Now;
Thread.Sleep(40);
}
Aircraft.Altitude = AltitudeChange.Altitude; // Altitude is reached
}
Upvotes: 0
Reputation: 2786
public bool AlttudeReached(double alt1, double alt2, double rateofClimb) {
return rateofClimb > 0 ? alt1 >= alt2 : alt2 >= alt1;
}
Upvotes: 1
Reputation: 19445
you can do it by looking for sign change:
private void AltitudeThreadWork()
{
bool isOrigPositive = Aircraft.Altitude - AltitudeChange.Altitude > 0;
do
{
var updated = DateTime.Now;
UpdateAltitude((DateTime.Now - updated).TotalMilliseconds);
Thread.Sleep(40);
bool isNowPositive = Aircraft.Altitude - AltitudeChange.Altitude > 0;
}
while (isOrigPositive == isNowPositive)
}
Upvotes: 2
Reputation: 4812
Problem with floats/doubles is that checking for equality is hard. Therefor you should use a 'range' in which you consider them "equal".
Covering both up and down in 1 line:
while(Math.Abs(Altitude - AltitudeChange.Altitude) > 0.0001)
Upvotes: 0
Reputation: 1500275
Basically you want to make sure you don't overshoot. So instead of checking for equality, check whether applying the change would take you further away from the target altitude, or closer towards it.
You might also want to change the thread that adjusts the altitude to stop overshooting to start with. So for example, pseudocode:
double potentialAltitude = currentAltitude + AltitudeChange;
if (AltitudeChange < 0) // Going down... don't go below the "floor"
{
newAltitude = Math.Max(potentialAltitude, TargetAltitude);
}
else // Going up... don't go above the "ceiling"
{
newAltitude = Math.Min(potentialAltitude, TargetAltitude);
}
Upvotes: 1