循环中的值比较,当值相等时打破循环的最佳方法
本文关键字:循环 方法 最佳 比较 | 更新日期: 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
}