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

Gen*_*rts 97 .net c# floating-point precision zero

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

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

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

double x = 0.0;
return (x == 0.0) ? true : false;
Run Code Online (Sandbox Code Playgroud)

这会永远回归真实吗?

Dan*_*nas 113

当且仅当double变量具有精确值时(当然,在原始代码片段中是这种情况),可以安全地期望比较将返回.这与运算符的语义一致.意思是" 等于".true0.0==a == bab

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


Dir*_*mar 50

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

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

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

double d1 = 10.0 * .1;
bool equals = d1.AlmostEquals(0.0, 0.0000001);
Run Code Online (Sandbox Code Playgroud)

  • 如果这些数字的值彼此非常接近,则可能通过比较double1和double2来获得减法消除错误.我会删除Math.Abs​​并单独检查每个分支d1> = d2 - e和d1 <= d2 + e (4认同)

Joe*_*orn 15

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

bool b = ( 10.0 * .1 - 1.0 == 0.0 );
Run Code Online (Sandbox Code Playgroud)

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

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

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

  • 实际上,由于某种原因,这会返回true(至少在LINQPad中). (4认同)

Stu*_*lar 13

Double.Equals的MSDN条目:

比较精度

应谨慎使用Equals方法,因为两个明显等效的值可能不相等,因为这两个值的精度不同.以下示例报告Double值.3333和通过除以1而返回的Double是不相等的.

...

一种推荐的技术不是比较相等性,而是涉及在两个值之间定义可接受的差异裕度(例如其中一个值的0.01%).如果两个值之间的差的绝对值小于或等于该边界,则差异可能是由于精度的差异,因此,值可能相等.以下示例使用此技术比较.33333和1/3,前两个代码示例发现的两个Double值不相等.

另请参阅Double.Epsilon.


Yog*_*gee 6

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

float f = 0.1F;
bool b1 = (f == 0.1); //returns false
bool b2 = (f == 0.1F); //returns true
Run Code Online (Sandbox Code Playgroud)

问题是,程序员有时会忘记隐式类型转换(double to float)正在进行比较,结果就是bug.