106

我知道您通常不能依赖 double 或 decimal 类型值之间的相等性,但我想知道 0 是否是一种特殊情况。

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

但我对这个话题了解不多,所以不由我说。

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

这总是会返回真实的吗?

4

9 回答 9

122

可以安全地预期,true当且仅当 double 变量的值恰好为时0.0(在您的原始代码片段中当然是这种情况),比较才会返回。这与运算符的语义一致==a == b表示“a等于b”。

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

于 2009-01-27T22:58:04.253 回答
53

如果您需要进行大量“相等”比较,最好在 .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);
于 2009-01-27T23:06:54.110 回答
15

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

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

请记住,0.1 是二进制重复的十进制数,不能精确表示,就像尝试将 1/3 写为以 10 为底的十进制数一样。现在将其与此代码进行比较:

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

我会让您进行测试以查看实际结果:您更有可能以这种方式记住它。

于 2009-01-27T20:58:16.633 回答
14

从Double.Equals的 MSDN 条目中:

比较精度

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

...

一种推荐的技术不是比较相等性,而是定义两个值之间的可接受差异范围(例如其中一个值的 0.01%)。如果两个值之间的差值的绝对值小于或等于该余量,则差异可能是由于精度差异造成的,因此这些值很可能相等。下面的示例使用此技术比较 .33333 和 1/3,这是前面的代码示例发现不相等的两个 Double 值。

另请参阅Double.Epsilon

于 2009-01-27T20:56:03.360 回答
6

当您比较不同类型的浮点值实现时会出现问题,例如将浮点数与双精度数进行比较。但是同类型的应该问题不大。

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

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

于 2011-09-08T12:55:34.513 回答
3

如果数字直接分配给浮点数或双精度数,则可以安全地针对零或任何整数进行测试,对于双精度数或浮点数可以以 53 位或 24 位表示。

或者换一种说法,您始终可以将整数值分配给双精度,然后将双精度与相同的整数进行比较,并保证它是相等的。

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

于 2009-01-27T22:07:08.943 回答
2

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

于 2009-04-10T15:27:05.287 回答
-2

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

这是来自Quora的答案。

于 2018-06-19T08:21:22.497 回答
-5

实际上,我认为最好使用以下代码将双精度值与 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;
于 2011-12-15T17:22:24.450 回答