将浮点值的相等性检查为0是否安全?

时间:2009-01-27 20:50:15

标签: c# .net floating-point precision zero

我知道你不能正常依赖双重或十进制类型值之间的相等,但我想知道0是否是特殊情况。

虽然我可以理解0.00000000000001和0.00000000000002之间的不精确,但是0本身似乎很难搞砸,因为它什么也没有。如果你对什么都不精确,那就不再是什么了。

但我对这个话题知之甚少,所以我不能说。

double x = 0.0;
return (x == 0.0) ? true : false;

这总是会回归吗?

9 个答案:

答案 0 :(得分:105)

安全,当且仅当双变量的值精确为true时,才会期望比较返回0.0(在原始代码段中为当然,这个案子)。这与==运算符的语义一致。 a == b表示“a等于b”。

不安全(因为不正确)期望某些计算的结果在double(或更一般地,浮点)算术中为零每当纯数学中相同计算的结果为零时。这是因为当计算出现时,会出现浮点精度误差 - 这个概念在数学中的实数算术中是不存在的。

答案 1 :(得分:47)

如果你需要进行大量的“相等”比较,那么在.NET 3.5中编写一个小帮助函数或扩展方法进行比较可能是一个好主意:

public static bool AlmostEquals(this double double1, double double2, double precision)
{
    return (Math.Abs(double1 - double2) <= precision);
}

这可以通过以下方式使用:

double d1 = 10.0 * .1;
bool equals = d1.AlmostEquals(0.0, 0.0000001);

答案 2 :(得分:15)

对于您的简单样本,该测试是可以的。但是这个怎么样:

bool b = ( 10.0 * .1 - 1.0 == 0.0 );

请记住.1是二进制的重复小数,无法准确表示。然后将其与此代码进行比较:

double d1 = 10.0 * .1; // make sure the compiler hasn't optimized the .1 issue away
bool b = ( d1 - 1.0 == 0.0 );

我会让你去做一个测试,看看实际的结果:你更有可能记住它。

答案 3 :(得分:13)

来自Double.Equals的MSDN条目:

  

比较精确度

     

Equals方法应该与。一起使用   谨慎,因为两个显然   等值可能是不等的   两者的精度不同   值。以下示例报告   那个Double值.3333和   通过除以1而得到的双是   不相等的。

     

...

     

而不是比较平等,   一种推荐的技术涉及   定义可接受的边际   两个值之间的差异(例如   其中一个值的.01%)。如果   差异的绝对值   两个值之间小于或   等于那个边际,差异   可能是由于差异造成的   精度,因此,价值   可能是平等的。下列   示例使用此技术进行比较   .33333和1/3,两个Double值   上一个代码示例找到了   不平等。

另请参阅Double.Epsilon

答案 4 :(得分:6)

当您比较不同类型的浮点值实现时问题就出现了,例如将float与double进行比较。但是同样的类型,它应该不是问题。

float f = 0.1F;
bool b1 = (f == 0.1); //returns false
bool b2 = (f == 0.1F); //returns true

问题是,程序员有时会忘记进行比较时会发生隐式类型转换(double to float),并导致错误。

答案 5 :(得分:3)

如果数字直接分配给浮点数或双数,那么可以安全地测试零或任何整数,可以用双位表示53位或浮点数用24位。

或者换句话说,你可以随时将double和integer赋值给double,然后将double与同一个整数进行比较,并保证它是相等的。

你也可以通过指定一个整数来开始,并通过坚持添加,减去或乘以整数来进行简单的比较(假设结果小于24位浮点数abd 53位为双数) 。因此,您可以在某些受控条件下将浮点数和双精度数视为整数。

答案 6 :(得分:2)

不,不行。当比较等于0.0时,所谓的非正规化值(次正规)将比较为假(非零),但是当在等式中使用时将被归一化(变为0.0)。因此,使用它作为避免被零除的机制是不安全的。相反,添加1.0并与1.0进行比较。这将确保将所有子范数视为零。

答案 7 :(得分:-1)

试试这个,你会发现==对于double / float来说是不可靠的 double d = 0.1 + 0.2; bool b = d == 0.3;

以下是Quora的answer

答案 8 :(得分:-4)

实际上,我认为最好使用以下代码将double值与0.0进行比较:

double x = 0.0;
return (Math.Abs(x) < double.Epsilon) ? true : false;

浮动相同:

float x = 0.0f;
return (Math.Abs(x) < float.Epsilon) ? true : false;