直接比较.net中的浮点数(double,float)是否相等是不安全的。变量中的double值可能会随着时间的推移而变化很小。例如,如果将变量num(double)设置为对象的0.2,则在该对象在内存中等待一段时间后,您可能会发现num变为0.1999999999999。因此,在这种情况下,num == 0.2将为false。我对这个问题的解决方案是创建一个属性来舍入数字:
double Num
{
get{ return Math.Round(num, 1); }
}
在调用Num的get并返回结果后,在比较时(Num == 0.2),这个返回的数字是否会再次变为0.19?它不太可能但是有保证吗?
答案 0 :(得分:6)
不,不能保证。
来自MSDN - Math.Round
:
此方法的行为遵循IEEE标准754第4节。这种舍入有时称为舍入到最近,或者是银行家的舍入。它最小化舍入错误,这是因为在单个方向上始终舍入中点值。
(强调我的)
点是 - 最小化,而不是确保。
在比较浮点类型时,您应该始终针对epsilon进行测试 - 这是您不关心的最小值。
改编自here的示例:
double dValue = 0.2;
var diff = Math.Abs(num - dValue);
if( diff < 0.0000001 ) // need some min threshold to compare floating points
{
// treat as equal
}
推荐阅读:What Every Computer Scientist Should Know About Floating-Point Arithmetic。
答案 1 :(得分:3)
无论您是否相信,这都是预期的行为,并且符合某些IEEE标准。
无法在单个二进制表示中表示模拟的每日值,例如大量数字或具有完全保真度的小部分。 .NET中的浮点数(例如float或double)在为数字赋值时尽量减少错误,因此当您为变量赋值0.2时,语言会尽力选择具有最小错误的表示。 / p>
这不是数字在某种程度上在内存中降级 - 这是一个刻意的步骤。如果要比较浮点数,则应始终允许比较任意一侧的区域。你的0.2表示接近非常大的小数位数。这对你的申请来说足够好吗?它看起来很刺眼,但实际上是一个非常小的错误。当比较双精度数和浮点数(整数或相互之间)时,应始终考虑可接受的精度,并接受预期结果任一侧的范围。
您还可以选择使用其他类型,例如decimal,它在小数位上具有极高的精度 - 但与浮点数和双精度数相比也非常大。
答案 2 :(得分:2)
变量本身不会改变。如果a == b在某个时间点,那么a == b将会更多,直到您修改a或b。
您可能遇到与浮点数据类型中的可表示性相关的问题,但不清楚问题是什么。很清楚的是,您当前的解决方案几乎肯定不是一个好主意。
答案 3 :(得分:0)
使用这样的代码来测试double是否相等:
public static bool AreEqual(double d1, double d2, double delta)
{
return Math.Abs(d1 - d2) < delta;
}