C# 检查浮点值是否等于 0 是否安全?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/485175/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Is it safe to check floating point values for equality to 0?
提问by Gene Roberts
I know you can't rely on equality between double or decimal type values normally, but I'm wondering if 0 is a special case.
我知道您通常不能依赖双精度或十进制类型值之间的相等性,但我想知道 0 是否是特例。
While I can understand imprecisions between 0.00000000000001 and 0.00000000000002, 0 itself seems pretty hard to mess up since it's just nothing. If you're imprecise on nothing, it's not nothing anymore.
虽然我可以理解 0.00000000000001 和 0.00000000000002 之间的不精确性,但 0 本身似乎很难搞砸,因为它什么都没有。如果你对什么都不精确,那它就不再是什么了。
But I don't know much about this topic so it's not for me to say.
但我对这个话题了解不多,所以我就不多说了。
double x = 0.0;
return (x == 0.0) ? true : false;
Will that always return true?
那总是会返回true吗?
采纳答案by Daniel Daranas
It is safeto expect that the comparison will return true
if and only if the double variable has a value of exactly 0.0
(which in your original code snippet is, of course, the case). This is consistent with the semantics of the ==
operator. a == b
means "a
is equal to b
".
当且仅当 double 变量的值恰好为 时(当然,在您的原始代码片段中就是这种情况),可以安全地期望比较会返回。这与操作符的语义一致。表示“等于”。true
0.0
==
a == b
a
b
It is not safe(because it is not correct) to expect that the result of some calculation will be zero in double (or more generally, floating point) arithmetics whenever the result of the same calculation in pure Mathematics is zero. This is because when calculations come into the ground, floating point precision error appears - a concept which does not exist in Real number arithmetics in Mathematics.
当纯数学中相同计算的结果为零时,期望某些计算的结果在双精度(或更一般地,浮点)算术中为零是不安全的(因为它不正确)。这是因为当计算进入地面时,会出现浮点精度误差 - 这个概念在数学中的实数算术中不存在。
回答by Stu Mackellar
From the MSDN entry for Double.Equals:
从Double.Equals的 MSDN 条目:
Precision in Comparisons
The Equals method should be used with caution, because two apparently equivalent values can be unequal due to the differing precision of the two values. The following example reports that the Double value .3333 and the Double returned by dividing 1 by 3 are unequal.
...
Rather than comparing for equality, one recommended technique involves defining an acceptable margin of difference between two values (such as .01% of one of the values). If the absolute value of the difference between the two values is less than or equal to that margin, the difference is likely to be due to differences in precision and, therefore, the values are likely to be equal. The following example uses this technique to compare .33333 and 1/3, the two Double values that the previous code example found to be unequal.
比较精度
应谨慎使用 Equals 方法,因为由于两个值的精度不同,两个明显等效的值可能不相等。下面的示例报告 Double 值 .3333 和由 1 除以 3 返回的 Double 不相等。
...
一种推荐的技术不是比较相等性,而是定义两个值之间可接受的差异幅度(例如其中一个值的 0.01%)。如果两个值之间的差值的绝对值小于或等于该裕度,则该差值很可能是由于精度差异造成的,因此,这些值很可能相等。下面的示例使用此技术来比较 0.33333 和 1/3,这两个 Double 值在前面的代码示例中发现不相等。
Also, see Double.Epsilon.
另请参阅Double.Epsilon。
回答by Joel Coehoorn
For your simple sample, that test is okay. But what about this:
对于您的简单示例,该测试没问题。但是这个呢:
bool b = ( 10.0 * .1 - 1.0 == 0.0 );
Remember that .1 is a repeating decimal in binary and can't be represented exactly. Then compare that to this code:
请记住,.1 是二进制中的重复十进制,无法准确表示。然后将其与此代码进行比较:
double d1 = 10.0 * .1; // make sure the compiler hasn't optimized the .1 issue away
bool b = ( d1 - 1.0 == 0.0 );
I'll leave you to run a test to see the actual results: you're more likely to remember it that way.
我会让你运行一个测试来查看实际结果:你更有可能以这种方式记住它。
回答by Kevin Gale
If the number was directly assigned to the float or double then it is safe to test against zero or any whole number that can be represented in 53 bits for a double or 24 bits for a float.
如果数字直接分配给浮点数或双精度数,则可以安全地针对零或任何整数进行测试,这些数字可以用 53 位表示双精度数或 24 位表示浮点数。
Or to put it another way you can always assign and integer value to a double and then compare the double back to the same integer and be guaranteed it will be equal.
或者换句话说,您始终可以将整数值分配给双精度数,然后将双精度数与相同的整数进行比较,并保证它是相等的。
You can also start out by assigning a whole number and have simple comparisons continue to work by sticking to adding, subtracting or multiplying by whole numbers (assuming the result is less than 24 bits for a float abd 53 bits for a double). So you can treat floats and doubles as integers under certain controlled conditions.
您也可以从分配一个整数开始,然后通过坚持加、减或乘以整数来继续进行简单的比较(假设浮点数的结果小于 24 位,双精度数为 53 位)。因此,您可以在某些受控条件下将浮点数和双精度数视为整数。
回答by Dirk Vollmar
If you need to do a lot of "equality" comparisons it might be a good idea to write a little helper function or extension method in .NET 3.5 for comparing:
如果您需要进行大量“相等”比较,最好在 .NET 3.5 中编写一些辅助函数或扩展方法进行比较:
public static bool AlmostEquals(this double double1, double double2, double precision)
{
return (Math.Abs(double1 - double2) <= precision);
}
This could be used the following way:
这可以通过以下方式使用:
double d1 = 10.0 * .1;
bool equals = d1.AlmostEquals(0.0, 0.0000001);
回答by Dirk Vollmar
No, it is not OK. So-called denormalized values (subnormal), when compared equal to 0.0, would compare as false (non-zero), but when used in an equation would be normalized (become 0.0). Thus, using this as a mechanism to avoid a divide-by-zero is not safe. Instead, add 1.0 and compare to 1.0. This will ensure that all subnormals are treated as zero.
不,这不行。所谓的非规范化值(次规范),当比较等于 0.0 时,将比较为假(非零),但在方程中使用时将规范化(变为 0.0)。因此,将其用作避免被零除的机制是不安全的。相反,添加 1.0 并与 1.0 进行比较。这将确保所有次正规都被视为零。
回答by Yogee
The problem comes when you are comparing different types of floating point value implementation e.g. comparing float with double. But with same type, it shouldn't be a problem.
当您比较不同类型的浮点值实现时会出现问题,例如比较 float 和 double。但是对于相同的类型,这应该不是问题。
float f = 0.1F;
bool b1 = (f == 0.1); //returns false
bool b2 = (f == 0.1F); //returns true
The problem is, programmer sometimes forgets that implicit type cast (double to float) is happening for the comparison and the it results into a bug.
问题是,程序员有时会忘记进行比较的隐式类型转换(双到浮点数),这会导致错误。
回答by David.Chu.ca
Actually, I think it is better to use the following codes to compare a double value against to 0.0:
实际上,我认为最好使用以下代码将双精度值与 0.0 进行比较:
double x = 0.0;
return (Math.Abs(x) < double.Epsilon) ? true : false;
Same for float:
浮动相同:
float x = 0.0f;
return (Math.Abs(x) < float.Epsilon) ? true : false;