循环中的值比较,当值相等时打破循环的最佳方法

本文关键字:循环 方法 最佳 比较 | 更新日期: 2023-09-27 17:56:34

假设一个具有两个属性的飞机类;海拔和海拔变化:

public class Aircraft  
{
    public double Altitude { get; set; }
    public AltitudeChange { get; set; }
}

高度变化有两个属性;海拔高度和爬升率:

public class AltitudeChange
{ 
    public double Altitude { get; set; }
    public double RateOfClimb { get; set; } //Negative for descent
}

如果我们有一个"工作线程",根据经过的时间和爬升率更新飞机的高度,那么确保在达到新高度时循环停止的理想设计/实现是什么?

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

例如,此线程不会停止攀登过程,因为双精度数字通常不会完全相等。

即使您将双精度转换为 int,您仍然不能 100% 确定这两个值是否相等。

循环中的值比较,当值相等时打破循环的最佳方法

你可以通过查找符号更改来做到这一点:

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)
}
基本上你要

确保你不会超调。因此,与其检查相等性,不如检查应用更改是否会使您离目标高度更远或更近。

您可能想更改调整高度的线程,以停止开始超调。例如,伪代码:

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);
}
    public bool AlttudeReached(double alt1, double alt2, double rateofClimb) {
        return rateofClimb > 0 ? alt1 >= alt2 : alt2 >= alt1;
    }

浮点数/双精度的问题在于检查相等性很困难。因此,您应该使用您认为它们"相等"的"范围"。

1 行中覆盖上下:

while(Math.Abs(Altitude - AltitudeChange.Altitude) > 0.0001)
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
}