After a bit of light reading, this article piqued my interest:
I'd have thought that yes, the two statements are equivalent, given MSDN's statement:
Represents the smallest positive Double value that is greater than zero. This field is constant.
Curious to see what people think.
EDIT: Found a computer with VS on and ran this Test. Turns out that yes, as expected, they're equivalent.
[Test]
public void EpsilonTest()
{
Compare(0d);
Compare(double.Epsilon);
Compare(double.Epsilon * 0.5);
Compare(double.NaN);
Compare(double.PositiveInfinity);
Compare(double.NegativeInfinity);
Compare(double.MaxValue);
Compare(double.MinValue);
}
public void Compare(double x)
{
Assert.AreEqual(Math.Abs(x) == 0d, Math.Abs(x) < double.Epsilon);
}
Yes, as far as I can tell they should be equivalent. This is because no difference can have a magnitude less than epsilon and also be nonzero.
My only thought was concerning values such as double.NaN, I tested that and PositiveInfinity, etc. and the results were the same. By the way, comparing double.NaN to a number returns false.
I'm not sure what you mean by "equivalent" here, as that's a pretty vague term.
If you mean, will .NET consider any value less than
double.Epsilon
to be equal to0d
, then yes, as the article you linked to clearly demonstrates. You can show this pretty easily:In that sense, if you somehow produce a value of
x
that is less thandouble.Epislon
, it will already be stored in-memory as a zero value, soAbs(x)
will just beAbs(0)
which is,== 0d
.But this is a limitation of the binary representation as used by .NET to hold floating point numbers: it simply can't represent a non-zero number smaller than
double.Epsilon
so it rounds.That doesn't mean the two statements are "equivalent", because that's entirely context-dependent. Clearly,
4.94065645841247E-324 * 0.5
is not zero, it is2.470328229206235e-324
. If you are doing calculations that require that level of precision, than no, they are not equivalent -- and you're also out of luck trying to do them in C#.In most cases, the value of
double.Epsilon
is entirely too small to be of any value, meaning thatAbs(x)
should== 0d
for values much larger thandouble.Epison
, but C# relies on you to figure that out; it will happily do the calculations down to that precision, if asked.Unfortunately, the statement "
Math.Abs(x) < double.Epsilon
is equivalent toMath.Abs(x) == 0d
" is not true at all for ARM systems.MSDN on Double.Epsilon contradicts itself by stating that
That means that on ARM systems, there are no non-negative double values less than
Double.Epsilon
, so the expressionMath.Abs(x) < double.Epsilon
is just another way to sayfalse
.IL code seems to cast some light on this.
Epsilon is simply a double number with the fraction part being 1, sign 0, exponent 0. Zero is a double number with the fraction part being 0, sign 0, exponent 0.
According to http://en.wikipedia.org/wiki/IEEE_754-1985, floating point numbers with the same sign and exponent are compared ordinally, which means that (x < 1) is the same as (x == 0).
Now, is it possible to get a zero that isn't fraction = 0, exponent = 0 (we don't care about sign, there's a Math.Abs in place)?