我知道您通常不能依赖 double 或 decimal 类型值之间的相等性,但我想知道 0 是否是一种特殊情况。
虽然我可以理解 0.00000000000001 和 0.00000000000002 之间的不精确性,但 0 本身似乎很难搞砸,因为它什么都不是。如果你什么都不精确,那它就不再是什么了。
但我对这个话题了解不多,所以不由我说。
double x = 0.0;
return (x == 0.0) ? true : false;
这总是会返回真实的吗?
我知道您通常不能依赖 double 或 decimal 类型值之间的相等性,但我想知道 0 是否是一种特殊情况。
虽然我可以理解 0.00000000000001 和 0.00000000000002 之间的不精确性,但 0 本身似乎很难搞砸,因为它什么都不是。如果你什么都不精确,那它就不再是什么了。
但我对这个话题了解不多,所以不由我说。
double x = 0.0;
return (x == 0.0) ? true : false;
这总是会返回真实的吗?
可以安全地预期,true
当且仅当 double 变量的值恰好为时0.0
(在您的原始代码片段中当然是这种情况),比较才会返回。这与运算符的语义一致==
。a == b
表示“a
等于b
”。
当纯数学中相同计算的结果为零时,期望某些计算的结果在双精度(或更一般地,浮点)算术中为零是不安全的(因为它是不正确的)。这是因为当计算落地时,会出现浮点精度误差——这是数学实数算术中不存在的概念。
如果您需要进行大量“相等”比较,最好在 .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);
对于您的简单样本,该测试是可以的。但是这个呢:
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 );
我会让您进行测试以查看实际结果:您更有可能以这种方式记住它。
从Double.Equals的 MSDN 条目中:
比较精度
应谨慎使用 Equals 方法,因为由于两个值的精度不同,两个明显等效的值可能不相等。下面的示例报告 Double 值 .3333 和通过将 1 除以 3 返回的 Double 不相等。
...
一种推荐的技术不是比较相等性,而是定义两个值之间的可接受差异范围(例如其中一个值的 0.01%)。如果两个值之间的差值的绝对值小于或等于该余量,则差异可能是由于精度差异造成的,因此这些值很可能相等。下面的示例使用此技术比较 .33333 和 1/3,这是前面的代码示例发现不相等的两个 Double 值。
另请参阅Double.Epsilon。
当您比较不同类型的浮点值实现时会出现问题,例如将浮点数与双精度数进行比较。但是同类型的应该问题不大。
float f = 0.1F;
bool b1 = (f == 0.1); //returns false
bool b2 = (f == 0.1F); //returns true
问题是,程序员有时会忘记隐式类型转换(double to float)是为了比较而发生的,这会导致错误。
如果数字直接分配给浮点数或双精度数,则可以安全地针对零或任何整数进行测试,对于双精度数或浮点数可以以 53 位或 24 位表示。
或者换一种说法,您始终可以将整数值分配给双精度,然后将双精度与相同的整数进行比较,并保证它是相等的。
您也可以从分配一个整数开始,并通过坚持加、减或乘以整数来继续进行简单的比较(假设结果小于 24 位浮点数和 53 位双精度数)。因此,您可以在某些受控条件下将浮点数和双精度数视为整数。
不,这样不行。所谓的非规格化值(次正规),当比较等于 0.0 时,会比较为假(非零),但在等式中使用时会被标准化(变为 0.0)。因此,将其用作避免被零除的机制是不安全的。相反,添加 1.0 并与 1.0 进行比较。这将确保所有次正规都被视为零。
试试这个,你会发现 == 对于 double/float 是不可靠的。
double d = 0.1 + 0.2;
bool b = d == 0.3;
这是来自Quora的答案。
实际上,我认为最好使用以下代码将双精度值与 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;