检查浮点值是否等于 0 是否安全?

问题描述 投票:0回答:10

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

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

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

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

这总是返回 true 吗?

c# .net floating-point precision zero
10个回答
124
投票
当且仅当 double 变量的值恰好为

true(当然,在您的原始代码片段中就是这种情况)时,期望比较将返回

0.0
安全
。这与
==
运算符的语义一致。
a == b
表示“
a
等于
b
”。

每当纯数学中相同计算的结果为零时,期望某些计算的结果在双精度(或更一般地说,浮点)算术中为零是“不安全”(因为它“不正确”) 。这是因为当计算落地时,会出现浮点精度误差——这是数学中实数运算中不存在的概念。 如果您需要进行大量“相等”比较,那么在 .NET 3.5 中编写一些辅助函数或扩展方法来进行比较可能是个好主意:


53
投票

可以通过以下方式使用:

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

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

15
投票

请记住,.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

14
投票

比较的精确性

Equals 方法应该与 小心,因为两个显然 由于等效值可能不相等 两者的精度不同 价值观。以下示例报告 Double 值 0.3333 和 1 除以 3 返回的双精度数为 不平等。 ...

与其比较平等, 一种推荐的技术涉及 定义可接受的余量 两个值之间的差异(例如 其中一个值的 .01%)。如果 差的绝对值 两个值之间小于或 等于该边距,差值 很可能是由于差异 精度,因此,值 很可能是相等的。下列 示例使用此技术进行比较 .33333 和 1/3,两个 Double 值 前面的代码示例发现 不平等。

另请参阅

Double.Epsilon

当您比较不同类型的浮点值实现时,问题就出现了,例如比较浮点型和双精度型。不过同类型的话应该没问题。


7
投票

问题是,程序员有时会忘记比较时发生了隐式类型转换(双精度型到浮点型),从而导致错误。


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


3
投票

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

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


2
投票

对于那些好奇的人来说,

0.3333…

0
投票
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 来说并不可靠。

-2
投票


这是来自 Quora 的

答案

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


-5
投票

浮动同样:

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

© www.soinside.com 2019 - 2024. All rights reserved.