我知道你通常不能依赖双精度或十进制类型值之间的相等性,但我想知道 0 是否是一种特殊情况。
虽然我可以理解 0.00000000000001 和 0.0000000000002 之间的不精确性,但 0 本身似乎很难搞乱,因为它什么都没有。如果你对任何事情都不精确,那么它就不再是什么了。
但是我对这个话题了解不多,所以不方便我说。
double x = 0.0;
return (x == 0.0) ? true : false;
这总是返回 true 吗?
true
(当然,在您的原始代码片段中就是这种情况)时,期望比较将返回
0.0
是安全。这与
==
运算符的语义一致。 a == b
表示“a
等于 b
”。
每当纯数学中相同计算的结果为零时,期望某些计算的结果在双精度(或更一般地说,浮点)算术中为零是“不安全”(因为它“不正确”) 。这是因为当计算落地时,会出现浮点精度误差——这是数学中实数运算中不存在的概念。 如果您需要进行大量“相等”比较,那么在 .NET 3.5 中编写一些辅助函数或扩展方法来进行比较可能是个好主意:
可以通过以下方式使用:
double d1 = 10.0 * .1;
bool equals = d1.AlmostEquals(0.0, 0.0000001);
对于您的简单示例,该测试是可以的。但是这个呢:
请记住,.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.EqualsEquals 方法应该与 小心,因为两个显然 由于等效值可能不相等 两者的精度不同 价值观。以下示例报告 Double 值 0.3333 和 1 除以 3 返回的双精度数为 不平等。 ...
与其比较平等, 一种推荐的技术涉及 定义可接受的余量 两个值之间的差异(例如 其中一个值的 .01%)。如果 差的绝对值 两个值之间小于或 等于该边距,差值 很可能是由于差异 精度,因此,值 很可能是相等的。下列 示例使用此技术进行比较 .33333 和 1/3,两个 Double 值 前面的代码示例发现 不平等。
另请参阅
Double.Epsilon
。
问题是,程序员有时会忘记比较时发生了隐式类型转换(双精度型到浮点型),从而导致错误。
如果数字直接分配给浮点数或双精度数,则可以安全地测试零或任何可以用 53 位(双精度数)或 24 位(浮点数)表示的整数。
您还可以从分配一个整数开始,然后通过坚持对整数进行加、减或乘来继续进行简单的比较(假设浮点型的结果小于 24 位,双精度型的结果小于 53 位)。因此,在某些受控条件下,您可以将浮点数和双精度数视为整数。
不,这样不行。所谓的非规格化值(次正规)在与 0.0 进行比较时将比较为假(非零),但在方程中使用时将被规格化(变为 0.0)。因此,使用它作为避免被零除的机制是不安全的。相反,添加 1.0 并与 1.0 进行比较。这将确保所有次正常都被视为零。
对于那些好奇的人来说,
0.3333…
1/3
的确切 IEEE 754 表示是:
mawk '$++NF = ($++_)/((__ = +$(_+_--)) ? __ : !__)' CONVFMT='%.16lX' | column -t
0.3 _ 3FD3333333333333
0.33 _ 3FD51EB851EB851F
0.333 _ 3FD54FDF3B645A1D
0.3333 _ 3FD554C985F06F69
0.33333 _ 3FD555475A31A4BE
0.333333 _ 3FD55553EF6B5D46
0.3333333 _ 3FD55555318ABC87
0.33333333 _ 3FD5555551C112DA
0.333333333 _ 3FD5555554F9B516
0.3333333333 _ 3FD55555554C2BB5
0.33333333333 _ 3FD5555555546AC5
0.333333333333 _ 3FD5555555553DE1
0.3333333333333 _ 3FD55555555552FD
0.33333333333333 _ 3FD5555555555519
0.333333333333333 _ 3FD555555555554F
0.3333333333333333 _ 3FD5555555555555 <— 16 3's
0.33333333333333333 _ 3FD5555555555555
0.333333333333333333 _ 3FD5555555555555
0.3333333333333333333 _ 3FD5555555555555
0.33333333333333333333 _ 3FD5555555555555
0.333333333333333333333 _ 3FD5555555555555
1 3 3FD5555555555555
试试这个,你会发现 == 对于 double/float 来说并不可靠。
浮动同样:
float x = 0.0f;
return (Math.Abs(x) < float.Epsilon) ? true : false;