473,412 Members | 4,594 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,412 software developers and data experts.

Meaning of Double.Epsilon

I am grappling with the idea of double.Epsilon. I have written the
following test:

[Test]
public void FuzzyDivisionTest()
{
double a = 0.33333d;
double b = 1d / 3d;

Assert.IsFalse(a == b, "Built-in == operator should not be
fuzzy");
Assert.IsTrue( a-b < double.Epsilon);
Assert.IsTrue( Math.Abs(a-b) < double.Epsilon);
Assert.IsTrue( Math.Abs(b-a) < double.Epsilon);
}

However, something is weird. The first 2 assertions pass, however the
last 2 fail. Is Math.Abs() losing my Epsilon value? Is that correct?
Nov 16 '05 #1
44 16263
Daniel <dh*****@yahoo.com> wrote:
I am grappling with the idea of double.Epsilon. I have written the
following test:

[Test]
public void FuzzyDivisionTest()
{
double a = 0.33333d;
double b = 1d / 3d;

Assert.IsFalse(a == b, "Built-in == operator should not be
fuzzy");
Assert.IsTrue( a-b < double.Epsilon);
Assert.IsTrue( Math.Abs(a-b) < double.Epsilon);
Assert.IsTrue( Math.Abs(b-a) < double.Epsilon);
}

However, something is weird. The first 2 assertions pass, however the
last 2 fail. Is Math.Abs() losing my Epsilon value? Is that correct?


Epsilon is the smallest positive non-zero value that a double can hold.
It will never be true (I *think*) that a != b and
Math.Abs(b-a) < double.Epsilon.

a-b is less than double.Epsilon because it's negative.

--
Jon Skeet - <sk***@pobox.com>
http://www.pobox.com/~skeet
If replying to the group, please do not mail me too
Nov 16 '05 #2
Jon
My interpretation of the Visual Studio help on this is that this reply is
partially correct. It is possible that
a != b
and
Math.Abs(b - a) < double.Epsilon

However the difference between a and b in your example is evidently larger
than double.Epsilon - it is 3.3333333(recurring)e-10, and double.Epsilon ==
4.94065645841247e-324

As the previous reply said, the reason the second assertion passes is that
a - b is negative.

"Jon Skeet [C# MVP]" <sk***@pobox.com> wrote in message
news:MP************************@msnews.microsoft.c om...
Daniel <dh*****@yahoo.com> wrote:
I am grappling with the idea of double.Epsilon. I have written the
following test:

[Test]
public void FuzzyDivisionTest()
{
double a = 0.33333d;
double b = 1d / 3d;

Assert.IsFalse(a == b, "Built-in == operator should not be
fuzzy");
Assert.IsTrue( a-b < double.Epsilon);
Assert.IsTrue( Math.Abs(a-b) < double.Epsilon);
Assert.IsTrue( Math.Abs(b-a) < double.Epsilon);
}

However, something is weird. The first 2 assertions pass, however the
last 2 fail. Is Math.Abs() losing my Epsilon value? Is that correct?


Epsilon is the smallest positive non-zero value that a double can hold.
It will never be true (I *think*) that a != b and
Math.Abs(b-a) < double.Epsilon.

a-b is less than double.Epsilon because it's negative.

--
Jon Skeet - <sk***@pobox.com>
http://www.pobox.com/~skeet
If replying to the group, please do not mail me too

Nov 16 '05 #3
"Jon Skeet [C# MVP]" <sk***@pobox.com> wrote in
news:MP************************@msnews.microsoft.c om...
Daniel <dh*****@yahoo.com> wrote:
I am grappling with the idea of double.Epsilon. I have written the
following test:

[Test]
public void FuzzyDivisionTest()
{
double a = 0.33333d;
double b = 1d / 3d;

Assert.IsFalse(a == b, "Built-in == operator should not be
fuzzy");
Assert.IsTrue( a-b < double.Epsilon);
Assert.IsTrue( Math.Abs(a-b) < double.Epsilon);
Assert.IsTrue( Math.Abs(b-a) < double.Epsilon);
}

However, something is weird. The first 2 assertions pass, however the
last 2 fail. Is Math.Abs() losing my Epsilon value? Is that correct?


Epsilon is the smallest positive non-zero value that a double can hold.
It will never be true (I *think*) that a != b and
Math.Abs(b-a) < double.Epsilon.


Yes, I think the docs about Double.Epsilon are actually wrong; Quote:
"Instead [of comparing double values with ==], determine if the two sides of
a comparison are close enough to equal for your purposes by comparing
whether the absolute value of the difference between the left and right-hand
sides is less than Epsilon."

I usually use something like "Math.Abs(a-b) < 1e-10", but I'm not sure if
this is common practice.

Niki
Nov 16 '05 #4
Jon <no****@nospamever.com> wrote:
My interpretation of the Visual Studio help on this is that this reply is
partially correct. It is possible that
a != b
and
Math.Abs(b - a) < double.Epsilon


Could you give an example? I believe that

Math.Abs(b-a) < double.Epsilon => b-a != 0 => b==a

It's the last step that I'm not sure about though - is it possible for
a and b to be different, but their difference to be so close to 0 as to
be unrepresentably small? It feels unlikely, but I know that intuition
is often horribly flawed when it comes to floating point maths.

--
Jon Skeet - <sk***@pobox.com>
http://www.pobox.com/~skeet
If replying to the group, please do not mail me too
Nov 16 '05 #5
Niki Estner <ni*********@cube.net> wrote:
Epsilon is the smallest positive non-zero value that a double can hold.
It will never be true (I *think*) that a != b and
Math.Abs(b-a) < double.Epsilon.


Yes, I think the docs about Double.Epsilon are actually wrong; Quote:
"Instead [of comparing double values with ==], determine if the two sides of
a comparison are close enough to equal for your purposes by comparing
whether the absolute value of the difference between the left and right-hand
sides is less than Epsilon."

I usually use something like "Math.Abs(a-b) < 1e-10", but I'm not sure if
this is common practice.


Yup - that seems a much better idea. Do you want to report the problem
to MS, or shall I?

--
Jon Skeet - <sk***@pobox.com>
http://www.pobox.com/~skeet
If replying to the group, please do not mail me too
Nov 16 '05 #6
"Jon Skeet [C# MVP]" <sk***@pobox.com> wrote in
news:MP************************@msnews.microsoft.c om...
Jon <no****@nospamever.com> wrote:
My interpretation of the Visual Studio help on this is that this reply is
partially correct. It is possible that
a != b
and
Math.Abs(b - a) < double.Epsilon


Could you give an example? I believe that

Math.Abs(b-a) < double.Epsilon => b-a != 0 => b==a

It's the last step that I'm not sure about though - is it possible for
a and b to be different, but their difference to be so close to 0 as to
be unrepresentably small? It feels unlikely, but I know that intuition
is often horribly flawed when it comes to floating point maths.


I guess it's possible if a and b are stored in 80-bit FPU registers: b-a (80
bit) could still be different form 0 (using an 80-bit comparison), but the
difference would be smaller than double.Epsilon. Also Math.Abs(b-a) would
actually return 0 (if not inlined) as b-a would get casted to a (64-bit)
double value.
Sample code (compares (double.Epsilon/2) with 0):

using System;
public class MyClass
{
public static void Main()
{
double a = double.Parse("2");
Console.WriteLine(0 == (double.Epsilon/a));
Console.WriteLine((double.Epsilon/a-0) < double.Epsilon);
}
}

Niki
Nov 16 '05 #7
"Jon Skeet [C# MVP]" <sk***@pobox.com> wrote in
news:MP************************@msnews.microsoft.c om...
Niki Estner <ni*********@cube.net> wrote:
> Epsilon is the smallest positive non-zero value that a double can hold.
> It will never be true (I *think*) that a != b and
> Math.Abs(b-a) < double.Epsilon.


Yes, I think the docs about Double.Epsilon are actually wrong; Quote:
"Instead [of comparing double values with ==], determine if the two sides
of
a comparison are close enough to equal for your purposes by comparing
whether the absolute value of the difference between the left and
right-hand
sides is less than Epsilon."

I usually use something like "Math.Abs(a-b) < 1e-10", but I'm not sure if
this is common practice.


Yup - that seems a much better idea. Do you want to report the problem
to MS, or shall I?


You're the MVP ;-)

Niki
Nov 16 '05 #8
Niki Estner <ni*********@cube.net> wrote:
It's the last step that I'm not sure about though - is it possible for
a and b to be different, but their difference to be so close to 0 as to
be unrepresentably small? It feels unlikely, but I know that intuition
is often horribly flawed when it comes to floating point maths.
I guess it's possible if a and b are stored in 80-bit FPU registers: b-a (80
bit) could still be different form 0 (using an 80-bit comparison), but the
difference would be smaller than double.Epsilon. Also Math.Abs(b-a) would
actually return 0 (if not inlined) as b-a would get casted to a (64-bit)
double value.


Aargh, yes. I knew there was a good reason to be hesitant :)
Sample code (compares (double.Epsilon/2) with 0):


<snip>

Good, thanks. Here's something interesting, based on your code:

using System;
public class MyClass
{
public static void Main()
{
double two = double.Parse("2");
double a = double.Epsilon/two;
double b = 0;
Console.WriteLine(a==b);
Console.WriteLine(Math.Abs(b-a) < double.Epsilon);
}
}

That prints out (on my box):
True
True

If you comment out the last line, however, it just prints out
False

Presumably the call to Math.Abs forces a and b to be "normal" 64-bit
values rather than just 80-bit registers, or something like that.

--
Jon Skeet - <sk***@pobox.com>
http://www.pobox.com/~skeet
If replying to the group, please do not mail me too
Nov 16 '05 #9
Niki Estner <ni*********@cube.net> wrote:
Yup - that seems a much better idea. Do you want to report the problem
to MS, or shall I?


You're the MVP ;-)


Righto. (Admittedly I didn't have any luck persuading them that
System.Decimal is a floating point type rather than a fixed point type
- although reporting it again with the online bug database for 2.0,
it's been accepted!)

--
Jon Skeet - <sk***@pobox.com>
http://www.pobox.com/~skeet
If replying to the group, please do not mail me too
Nov 16 '05 #10
"Jon Skeet [C# MVP]" <sk***@pobox.com> wrote in
news:MP************************@msnews.microsoft.c om...
Niki Estner <ni*********@cube.net> wrote:
<snip>
Good, thanks. Here's something interesting, based on your code:

using System;
public class MyClass
{
public static void Main()
{
double two = double.Parse("2");
double a = double.Epsilon/two;
double b = 0;
Console.WriteLine(a==b);
Console.WriteLine(Math.Abs(b-a) < double.Epsilon);
}
}

That prints out (on my box):
True
True

If you comment out the last line, however, it just prints out
False

Presumably the call to Math.Abs forces a and b to be "normal" 64-bit
values rather than just 80-bit registers, or something like that.


Yes, I never really understood when variables get enregistered and when not.
And the fact that the rules change as soon as I attach a debugger doesn't
make it easier either...

Niki
Nov 16 '05 #11
Niki Estner <ni*********@cube.net> wrote:
Presumably the call to Math.Abs forces a and b to be "normal" 64-bit
values rather than just 80-bit registers, or something like that.


Yes, I never really understood when variables get enregistered and when not.
And the fact that the rules change as soon as I attach a debugger doesn't
make it easier either...


I'm glad I'm not the only one - your previous posts suggest that you
know far more about JIT optimisation than I'm ever likely to :)

--
Jon Skeet - <sk***@pobox.com>
http://www.pobox.com/~skeet
If replying to the group, please do not mail me too
Nov 16 '05 #12
"Jon Skeet [C# MVP]" <sk***@pobox.com> wrote in
news:MP************************@msnews.microsoft.c om...
Niki Estner <ni*********@cube.net> wrote:
> Presumably the call to Math.Abs forces a and b to be "normal" 64-bit
> values rather than just 80-bit registers, or something like that.


Yes, I never really understood when variables get enregistered and when
not.
And the fact that the rules change as soon as I attach a debugger doesn't
make it easier either...


I'm glad I'm not the only one - your previous posts suggest that you
know far more about JIT optimisation than I'm ever likely to :)


Thanks a lot :-)
Unfortunately I'm guessing blindly more often than I'd like to, too...

I think it would be a wise decision if MS would at least release a little
more documentation on the internals of the JIT: Many developers simply
assume it doesn't optimize at all, others try to "optimize" their code and
break real optimizations that way (register-variables are quite fragile) or
create unmaintainable code. At least a few rules of thumb (when will it
remove range checking? when will it inline a function? when will it
enregister a variable? etc.) would be very helpful here...

On the other hand, we probably wouldn't have any use for cordbg any more
then; Wouldn't that be a shame?

Niki
Nov 16 '05 #13
Jon - thanks for the reply, I was hoping to hear from you or John
Bentley, the recognized leaders on the internet in this area!

*** Sent via Developersdex http://www.developersdex.com ***
Don't just participate in USENET...get rewarded for it!
Nov 16 '05 #14
I tend to say that operators == result is undefined for floating point types
(except decimal).
You never know how variables are stored in memory. testing for equality for
a floating point variables never makes sense, even if you do:

float a = 1f;
float b = 1f;
if (a==b) { }

The Jitter may choose to place a and b in difference register types (32, 64
or 80 bits), so a==b may return true or false depending on the machine type,
framework version, debug or release settings or if a debugger is attached or
in which way the variables are used in code or wheather the method is
inlined or not.

So it would be great if the compiler would at least issue a warning if it
spots code which tests for equality with floating point values.

The only thing I could imagine is testing for NaN but in that case one
should use IsNaN() methods of struct Double and Single.

--
cody

Freeware Tools, Games and Humour
http://www.deutronium.de.vu || http://www.deutronium.tk
"Jon Skeet [C# MVP]" <sk***@pobox.com> schrieb im Newsbeitrag
news:MP************************@msnews.microsoft.c om...
Niki Estner <ni*********@cube.net> wrote:
It's the last step that I'm not sure about though - is it possible for
a and b to be different, but their difference to be so close to 0 as to be unrepresentably small? It feels unlikely, but I know that intuition
is often horribly flawed when it comes to floating point maths.


I guess it's possible if a and b are stored in 80-bit FPU registers: b-a (80 bit) could still be different form 0 (using an 80-bit comparison), but the difference would be smaller than double.Epsilon. Also Math.Abs(b-a) would actually return 0 (if not inlined) as b-a would get casted to a (64-bit)
double value.


Aargh, yes. I knew there was a good reason to be hesitant :)
Sample code (compares (double.Epsilon/2) with 0):


<snip>

Good, thanks. Here's something interesting, based on your code:

using System;
public class MyClass
{
public static void Main()
{
double two = double.Parse("2");
double a = double.Epsilon/two;
double b = 0;
Console.WriteLine(a==b);
Console.WriteLine(Math.Abs(b-a) < double.Epsilon);
}
}

That prints out (on my box):
True
True

If you comment out the last line, however, it just prints out
False

Presumably the call to Math.Abs forces a and b to be "normal" 64-bit
values rather than just 80-bit registers, or something like that.

--
Jon Skeet - <sk***@pobox.com>
http://www.pobox.com/~skeet
If replying to the group, please do not mail me too

Nov 16 '05 #15
Damn. Errata:

NaN cannot be used to test for is-not-a-number anyway. You *have to* use
IsNaN instead.
The same is true for NegativeInfinity and PositiveInfinity.

--
cody

Freeware Tools, Games and Humour
http://www.deutronium.de.vu || http://www.deutronium.tk
"cody" <no****************@gmx.net> schrieb im Newsbeitrag
news:#L**************@tk2msftngp13.phx.gbl...
I tend to say that operators == result is undefined for floating point types (except decimal).
You never know how variables are stored in memory. testing for equality for a floating point variables never makes sense, even if you do:

float a = 1f;
float b = 1f;
if (a==b) { }

The Jitter may choose to place a and b in difference register types (32, 64 or 80 bits), so a==b may return true or false depending on the machine type, framework version, debug or release settings or if a debugger is attached or in which way the variables are used in code or wheather the method is
inlined or not.

So it would be great if the compiler would at least issue a warning if it
spots code which tests for equality with floating point values.

The only thing I could imagine is testing for NaN but in that case one
should use IsNaN() methods of struct Double and Single.

--
cody

Freeware Tools, Games and Humour
http://www.deutronium.de.vu || http://www.deutronium.tk
"Jon Skeet [C# MVP]" <sk***@pobox.com> schrieb im Newsbeitrag
news:MP************************@msnews.microsoft.c om...
Niki Estner <ni*********@cube.net> wrote:
> It's the last step that I'm not sure about though - is it possible for > a and b to be different, but their difference to be so close to 0 as to > be unrepresentably small? It feels unlikely, but I know that intuition > is often horribly flawed when it comes to floating point maths.

I guess it's possible if a and b are stored in 80-bit FPU registers: b-a
(80
bit) could still be different form 0 (using an 80-bit comparison), but the difference would be smaller than double.Epsilon. Also Math.Abs(b-a) would actually return 0 (if not inlined) as b-a would get casted to a

(64-bit) double value.


Aargh, yes. I knew there was a good reason to be hesitant :)
Sample code (compares (double.Epsilon/2) with 0):


<snip>

Good, thanks. Here's something interesting, based on your code:

using System;
public class MyClass
{
public static void Main()
{
double two = double.Parse("2");
double a = double.Epsilon/two;
double b = 0;
Console.WriteLine(a==b);
Console.WriteLine(Math.Abs(b-a) < double.Epsilon);
}
}

That prints out (on my box):
True
True

If you comment out the last line, however, it just prints out
False

Presumably the call to Math.Abs forces a and b to be "normal" 64-bit
values rather than just 80-bit registers, or something like that.

--
Jon Skeet - <sk***@pobox.com>
http://www.pobox.com/~skeet
If replying to the group, please do not mail me too


Nov 16 '05 #16

"cody" <no****************@gmx.net> schrieb im Newsbeitrag
news:%2****************@tk2msftngp13.phx.gbl...
I tend to say that operators == result is undefined for floating point
types
(except decimal).
You never know how variables are stored in memory.
Of course you do. The *memory* size is determined by the variable's type.
testing for equality for
a floating point variables never makes sense, even if you do:

float a = 1f;
float b = 1f;
if (a==b) { }

The Jitter may choose to place a and b in difference register types (32,
64
or 80 bits), so a==b may return true or false depending on the machine
type,
framework version, debug or release settings or if a debugger is attached
or
in which way the variables are used in code or wheather the method is
inlined or not.
No, I'm pretty sure (a==b) will always be true here: AFAIK it's guaranteed
that converting a 32-bit floating point value to 64 bit or 80 bit will never
cause any loss in precision; Also, you're guaranteed that a 64-bit value
will never be stored in a 32-bit or smaller register (note that intel FPU's
don't have 32-bit or 64-bit registers anyway). So, in the case of constants
the '==' operator should always work correctly.
So it would be great if the compiler would at least issue a warning if it
spots code which tests for equality with floating point values.


It's common to test a floating point value for some constant it's
initialized to (like: if (a == 0) a = GetSomeValue();). Other tests for
common values (e.g. double.Parse(str) == 1) will work, too.
A warning wouldn't hurt (if it can be turned off), but I would prefer a
special "about equal" operator with fuzzy comparison rules.

Niki
Nov 16 '05 #17
Niki Estner <ni*********@cube.net> wrote:
So it would be great if the compiler would at least issue a warning if it
spots code which tests for equality with floating point values.


It's common to test a floating point value for some constant it's
initialized to (like: if (a == 0) a = GetSomeValue();). Other tests for
common values (e.g. double.Parse(str) == 1) will work, too.
A warning wouldn't hurt (if it can be turned off), but I would prefer a
special "about equal" operator with fuzzy comparison rules.


I don't think I'd want an operator, but a utility method on Double
wouldn't hurt. It could either take the two values and the "fuzziness
factor", or there could perhaps be a default fuzziness factor which
could be changed programatically.

--
Jon Skeet - <sk***@pobox.com>
http://www.pobox.com/~skeet
If replying to the group, please do not mail me too
Nov 16 '05 #18
> >I tend to say that operators == result is undefined for floating point
types
(except decimal).
You never know how variables are stored in memory.
Of course you do. The *memory* size is determined by the variable's type.


Yes in memory, but you do not know which CPU registers will be used.
No, I'm pretty sure (a==b) will always be true here: AFAIK it's guaranteed
that converting a 32-bit floating point value to 64 bit or 80 bit will never cause any loss in precision;
Maybe not precision but it will not be exactly the same value.
The following program outputs "true true false false" on my machine:

double d=0.0;
float f=0.0f;
double d1=1.0;
float f1=1.0f;
double d2=1.3;
float f2=1.3f;
float f3=float.Parse("0.2");
float f4=0.2f;
MessageBox.Show(string.Format("{0} {1} {2} {3}", d==f, d1==f1, d2==f2,
f3==f4));
Also, you're guaranteed that a 64-bit value
will never be stored in a 32-bit or smaller register
Thats clear. It it only guaranteed that a variable size 32 bit will be
stored in a register with *at least* 32 bit or more.

So, in the case of constants the '==' operator should always work
correctly.

It won't see above.
It's common to test a floating point value for some constant it's
initialized to (like: if (a == 0) a = GetSomeValue();). Other tests for
common values (e.g. double.Parse(str) == 1) will work, too.
If you are lucky it will work on some machines with some values.
A warning wouldn't hurt (if it can be turned off), but I would prefer a
special "about equal" operator with fuzzy comparison rules.


I'd vote against it. Testing equality is always bad idea anyway. Even if,
there must be a possibility to specify the tolerance value because the
fuzzyness really depends on the application. The method wouldn't do anything
else but Math.Abs(a,b)<Tolerance so there is very little point for including
such a method in the framework.

--
cody

Freeware Tools, Games and Humour
http://www.deutronium.de.vu || http://www.deutronium.tk
Nov 16 '05 #19
"cody" <no****************@gmx.net> wrote in
news:uc*************@TK2MSFTNGP11.phx.gbl...
...
Maybe not precision but it will not be exactly the same value.
The following program outputs "true true false false" on my machine:

double d=0.0;
float f=0.0f;
double d1=1.0;
float f1=1.0f;
double d2=1.3;
float f2=1.3f;
float f3=float.Parse("0.2");
float f4=0.2f;
MessageBox.Show(string.Format("{0} {1} {2} {3}", d==f, d1==f1, d2==f2,
f3==f4));
...


The point is that
float a=1.3f;
double b=1.3f;
Console.WriteLine(a==b);
Will always return true, because converting "1.3f" (or any other 32-bit
float-value) to double will not change it; Of course this value can actually
be different from "1.3d".

Your original example was:
float a = 1f;
float b = 1f;
if (a==b) { }

As shown above, "1f" (or any other float constant) will not be changed when
converted to a double (or 80-bit fp value), so that kind of comparison *is*
safe.

Niki
Nov 16 '05 #20
"cody" wrote:
I tend to say that operators == result is undefined for floating point
types
(except decimal).
You never know how variables are stored in memory.


Of course you do. The *memory* size is determined by the variable's type.


Yes in memory, but you do not know which CPU registers will be used.
No, I'm pretty sure (a==b) will always be true here: AFAIK it's guaranteed
that converting a 32-bit floating point value to 64 bit or 80 bit will

never
cause any loss in precision;


Maybe not precision but it will not be exactly the same value.
The following program outputs "true true false false" on my machine:

double d=0.0;
float f=0.0f;
double d1=1.0;
float f1=1.0f;
double d2=1.3;
float f2=1.3f;
float f3=float.Parse("0.2");
float f4=0.2f;
MessageBox.Show(string.Format("{0} {1} {2} {3}", d==f, d1==f1, d2==f2,
f3==f4));
Also, you're guaranteed that a 64-bit value
will never be stored in a 32-bit or smaller register


Thats clear. It it only guaranteed that a variable size 32 bit will be
stored in a register with *at least* 32 bit or more.

So, in the case of constants the '==' operator should always work
correctly.

It won't see above.
It's common to test a floating point value for some constant it's
initialized to (like: if (a == 0) a = GetSomeValue();). Other tests for
common values (e.g. double.Parse(str) == 1) will work, too.


If you are lucky it will work on some machines with some values.
A warning wouldn't hurt (if it can be turned off), but I would prefer a
special "about equal" operator with fuzzy comparison rules.


I'd vote against it. Testing equality is always bad idea anyway. Even if,
there must be a possibility to specify the tolerance value because the
fuzzyness really depends on the application. The method wouldn't do anything
else but Math.Abs(a,b)<Tolerance so there is very little point for including
such a method in the framework.

--
cody

Freeware Tools, Games and Humour
http://www.deutronium.de.vu || http://www.deutronium.tk


Equality comparison between integers (within the range and precision of your
chosen data type) and rational numbers of the form x/(2^y) ought to always
work. Other than that, you get into the ugliness of trying to losslessly
convert non-integral values between bases. (We all know how fun it is to
write out 1/3 as an "exact" decimal.)

Nov 16 '05 #21
> > Maybe not precision but it will not be exactly the same value.
The following program outputs "true true false false" on my machine:

double d=0.0;
float f=0.0f;
double d1=1.0;
float f1=1.0f;
double d2=1.3;
float f2=1.3f;
float f3=float.Parse("0.2");
float f4=0.2f;
MessageBox.Show(string.Format("{0} {1} {2} {3}", d==f, d1==f1, d2==f2,
f3==f4));
...
The point is that
float a=1.3f;
double b=1.3f;
Console.WriteLine(a==b);
Will always return true, because converting "1.3f" (or any other 32-bit
float-value) to double will not change it; Of course this value can

actually be different from "1.3d".
But the comparison returned FALSE! Did you read my posting?
Your original example was:
float a = 1f;
float b = 1f;
if (a==b) { }

As shown above, "1f" (or any other float constant) will not be changed when converted to a double (or 80-bit fp value), so that kind of comparison *is* safe.


This could cause the same problem as my first example. I can remember that
soem time ago someone gave me an example of values which really were
difference although there were both float and originally the same constant
was assigned to them.

--
cody

Freeware Tools, Games and Humour
http://www.deutronium.de.vu || http://www.deutronium.tk
Nov 16 '05 #22
"cody" <no****************@gmx.net> wrote in
news:%2****************@TK2MSFTNGP09.phx.gbl...
...
But the comparison returned FALSE! Did you read my posting?


Cody, please! Correct your code to:

double d=0.0f;
float f=0.0f;
double d1=1.0f;
float f1=1.0f;
double d2=1.3f;
float f2=1.3f;
float f3=float.Parse("0.2");
float f4=0.2f;

Because that's what we've been talking about: converting a 32-bit float to a
64-bit float won't change it's value.
So, it's always safe to compare a 32-bit float with another 32-bit float,
even if the JITer chooses to put it in a 80-bit FPU register.
Your original example was:
float a = 1f;
float b = 1f;
if (a==b) { }

As shown above, "1f" (or any other float constant) will not be changed

when
converted to a double (or 80-bit fp value), so that kind of comparison

*is*
safe.


This could cause the same problem as my first example. I can remember that
soem time ago someone gave me an example of values which really were
difference although there were both float and originally the same constant
was assigned to them.


So, why don't you show that example?

Look, a 32-bit FP number has 1 sign bit, 8 bits exponent and 23 mantissa
bits.
A 64-bit FP number has 1 sign bit, 11 bits for the exponent, and 52 bits for
the mantissa part.
If you convert a 32-bit fp to a 64-bit fp number, all you have to do is
"append zeros" to the mantissa part, which doesn't change it's value, and
convert the exponent from 8 to 11 bits (which doesn't change it either). So,
how do you think something like this
float f1 = SomeValue;
Console.Writeline(f1 == (double)f1);
could ever return false (unless SomeValue was NaN, of course)?

Niki
Nov 16 '05 #23
> > But the comparison returned FALSE! Did you read my posting?

Cody, please! Correct your code to:
[..] double d2=1.3f;
float f2=1.3f; [..]
Damn you are right.. A very subtle difference. Now I understand. 1.3 is not
equal to 1.3f, but 1.3f is always 1.3f, no matter if it is put into a float
or double variable or stored in a 64 or 80 bit register.
Look, a 32-bit FP number has 1 sign bit, 8 bits exponent and 23 mantissa
bits.
A 64-bit FP number has 1 sign bit, 11 bits for the exponent, and 52 bits for the mantissa part.
If you convert a 32-bit fp to a 64-bit fp number, all you have to do is
"append zeros" to the mantissa part, which doesn't change it's value, and
convert the exponent from 8 to 11 bits (which doesn't change it either).


Very interesting information.

But I could swear I read somewhere that the register will affect the
comparison :)

--
cody

[Freeware, Games and Humor]
www.deutronium.de.vu || www.deutronium.tk
Nov 16 '05 #24
cody <pl*************************@gmx.de> wrote:
If you convert a 32-bit fp to a 64-bit fp number, all you have to do is
"append zeros" to the mantissa part, which doesn't change it's value, and
convert the exponent from 8 to 11 bits (which doesn't change it either).


Very interesting information.

But I could swear I read somewhere that the register will affect the
comparison :)


It can if the conversion goes the other way - if a register holds an 80
bit number and that's converted to a 64 bit number.

Here's an example which actually didn't show up the problem on your box
last time I posted it, but it does show it on mine:

using System;

class Test
{
static float member;

static void Main()
{
member = Calc();
float local = Calc();
Console.WriteLine(local==member);
}

static float Calc()
{
float d1 = 2.82323f;
float d2 = 2.3f;
return d1*d2;
}
}

The member variable is strictly 32 bits, but the local variable can be
enregistered - so it ends up being more accurate than the member
variable, and the comparison fails (on my box).

--
Jon Skeet - <sk***@pobox.com>
http://www.pobox.com/~skeet
If replying to the group, please do not mail me too
Nov 16 '05 #25
> > > If you convert a 32-bit fp to a 64-bit fp number, all you have to do
is
"append zeros" to the mantissa part, which doesn't change it's value, and convert the exponent from 8 to 11 bits (which doesn't change it
either).
Very interesting information.

But I could swear I read somewhere that the register will affect the
comparison :)


It can if the conversion goes the other way - if a register holds an 80
bit number and that's converted to a 64 bit number.

Here's an example which actually didn't show up the problem on your box
last time I posted it, but it does show it on mine:

using System;

class Test
{
static float member;

static void Main()
{
member = Calc();
float local = Calc();
Console.WriteLine(local==member);
}

static float Calc()
{
float d1 = 2.82323f;
float d2 = 2.3f;
return d1*d2;
}
}

The member variable is strictly 32 bits, but the local variable can be
enregistered - so it ends up being more accurate than the member
variable, and the comparison fails (on my box).

Now I remember it was you with the example. But I still do not get it.
The explanation given by Niki seemed logical.
So if we never know which variable is put in which register so we can never
rely on that a comparison of two floating point variables will succeed?
So it stands as it is: Equality testing with floating point variables is
never a good idea because the result is undefined.

--
cody

Freeware Tools, Games and Humour
http://www.deutronium.de.vu || http://www.deutronium.tk
Nov 16 '05 #26
cody <no****************@gmx.net> wrote:
The member variable is strictly 32 bits, but the local variable can be
enregistered - so it ends up being more accurate than the member
variable, and the comparison fails (on my box).


Now I remember it was you with the example. But I still do not get it.
The explanation given by Niki seemed logical.
So if we never know which variable is put in which register so we can never
rely on that a comparison of two floating point variables will succeed?
So it stands as it is: Equality testing with floating point variables is
never a good idea because the result is undefined.


If the result is from a calculation, that's right. I believe that if
it's from a constant, or if it's from a calculation which has an answer
which can be exactly represented in the chosen data size, it's fine.

I suspect it's very, very rarely a good idea to use == for comparisons
with non-constants in the first place though.

--
Jon Skeet - <sk***@pobox.com>
http://www.pobox.com/~skeet
If replying to the group, please do not mail me too
Nov 16 '05 #27
"Jon Skeet [C# MVP]" <sk***@pobox.com> wrote in
news:MP************************@msnews.microsoft.c om...
cody <no****************@gmx.net> wrote:
> The member variable is strictly 32 bits, but the local variable can be
> enregistered - so it ends up being more accurate than the member
> variable, and the comparison fails (on my box).
Now I remember it was you with the example. But I still do not get it.
The explanation given by Niki seemed logical.
So if we never know which variable is put in which register so we can
never
rely on that a comparison of two floating point variables will succeed?
So it stands as it is: Equality testing with floating point variables is
never a good idea because the result is undefined.


If the result is from a calculation, that's right. I believe that if
it's from a constant, or if it's from a calculation which has an answer
which can be exactly represented in the chosen data size, it's fine.


Constant are ok, but calculation results usually aren't safe:
Console.WriteLine(Math.Sqrt(2)*Math.Sqrt(2) == 2);
prints out false on my machine.
I suspect it's very, very rarely a good idea to use == for comparisons
with non-constants in the first place though.


I'd definitely agree to that.

Niki
Nov 16 '05 #28
Niki Estner <ni*********@cube.net> wrote:
If the result is from a calculation, that's right. I believe that if
it's from a constant, or if it's from a calculation which has an answer
which can be exactly represented in the chosen data size, it's fine.


Constant are ok, but calculation results usually aren't safe:
Console.WriteLine(Math.Sqrt(2)*Math.Sqrt(2) == 2);
prints out false on my machine.


Well, I'd say that's a slightly different problem again - that's just
the general inaccuracies of floating point arithmetic, rather than
being due to conversions from an 80-bit value to a 64-bit value. I
think it's unreasonable to expect the above to print True necessarily,
but take:

double b = Math.Sqrt(2);
Console.WriteLine (b==Math.Sqrt(2));

I think it's reasonable to expect that to print True, but it may not.
(I'm not saying it's a bad thing for it not to, other than being
counter-intuitive. I understand the reasons for why things work the way
they do.)

--
Jon Skeet - <sk***@pobox.com>
http://www.pobox.com/~skeet
If replying to the group, please do not mail me too
Nov 16 '05 #29
> >> > The member variable is strictly 32 bits, but the local variable can
be
> enregistered - so it ends up being more accurate than the member
> variable, and the comparison fails (on my box).

Now I remember it was you with the example. But I still do not get it.
The explanation given by Niki seemed logical.
So if we never know which variable is put in which register so we can
never
rely on that a comparison of two floating point variables will succeed? So it stands as it is: Equality testing with floating point variables is never a good idea because the result is undefined.
If the result is from a calculation, that's right. I believe that if
it's from a constant, or if it's from a calculation which has an answer
which can be exactly represented in the chosen data size, it's fine.
But in Jons example the calculation can be left can certainly out without
altering the meaning the program because it compares the results of two same
calculations using constants only.
Constant are ok, but calculation results usually aren't safe:
Console.WriteLine(Math.Sqrt(2)*Math.Sqrt(2) == 2);
prints out false on my machine.


I wouldn't have expected any other result than a random value from 'true'
and 'false' :)

I always have been thinking of floating point values as "fuzzy things" where
the exact representation of the result of a calculation is not foreseeable.
Maybe there are IEEE standards but who knows where some machines calculates
floating point in their own way? I do not care as long as the result comes
very close to the "real" exact result.
I suspect it's very, very rarely a good idea to use == for comparisons
with non-constants in the first place though.


I'd definitely agree to that.


Who wouldn't agree with that (except the microsoft guy who decided that
operator== for fp do not need a compiler warning).

--
cody

[Freeware, Games and Humor]
www.deutronium.de.vu || www.deutronium.tk
Nov 16 '05 #30
cody <pl*************************@gmx.de> wrote:
If the result is from a calculation, that's right. I believe that if
it's from a constant, or if it's from a calculation which has an answer
which can be exactly represented in the chosen data size, it's fine.
But in Jons example the calculation can be left can certainly out without
altering the meaning the program because it compares the results of two same
calculations using constants only.


The calculation *uses* constants, but the result of it isn't
expressable exactly in 64 bits. That's the difference - any constant is
basically defined to be "the 64-bit (or 32-bit in case of float) value
closest to what is literally specified". It would be an error (I
believe) for an enregistered variable to take a more accurate value.
Constant are ok, but calculation results usually aren't safe:
Console.WriteLine(Math.Sqrt(2)*Math.Sqrt(2) == 2);
prints out false on my machine.


I wouldn't have expected any other result than a random value from 'true'
and 'false' :)

I always have been thinking of floating point values as "fuzzy things" where
the exact representation of the result of a calculation is not foreseeable.
Maybe there are IEEE standards but who knows where some machines calculates
floating point in their own way? I do not care as long as the result comes
very close to the "real" exact result.


I believe the result of a particular calculation is and can be
foreseeable. The difficulty here isn't with the calculation, or even
*how* the result is truncated to 64 bits - it's *when* the result is
truncated.
I suspect it's very, very rarely a good idea to use == for comparisons
with non-constants in the first place though.


I'd definitely agree to that.


Who wouldn't agree with that (except the microsoft guy who decided that
operator== for fp do not need a compiler warning).


I'm in two minds about that, personally. I can see the argument for a
warning, but at the same time it feels odd.

--
Jon Skeet - <sk***@pobox.com>
http://www.pobox.com/~skeet
If replying to the group, please do not mail me too
Nov 16 '05 #31
> I believe the result of a particular calculation is and can be
foreseeable. The difficulty here isn't with the calculation, or even
*how* the result is truncated to 64 bits - it's *when* the result is
truncated.

This is imho absolutely unforeseeable and depends on the cpu, the jitter and
so on.
> I suspect it's very, very rarely a good idea to use == for comparisons > with non-constants in the first place though.

I'd definitely agree to that.


Who wouldn't agree with that (except the microsoft guy who decided that
operator== for fp do not need a compiler warning).


I'm in two minds about that, personally. I can see the argument for a
warning, but at the same time it feels odd.


It may feel a bit odd but I do not think one of us ever used == on a
floating point value in a real application.
The only thing I can think of is if (a!=a) to test for NaN but we have
IsNan() for that.

--
cody

[Freeware, Games and Humor]
www.deutronium.de.vu || www.deutronium.tk
Nov 16 '05 #32
cody <pl*************************@gmx.de> wrote:
I believe the result of a particular calculation is and can be
foreseeable. The difficulty here isn't with the calculation, or even
*how* the result is truncated to 64 bits - it's *when* the result is
truncated.


This is imho absolutely unforeseeable and depends on the cpu, the
jitter and so on.


Yes - but the point I'm making is that it's not the same as the
calculation itself varying in its results.
I'm in two minds about that, personally. I can see the argument for a
warning, but at the same time it feels odd.


It may feel a bit odd but I do not think one of us ever used == on a
floating point value in a real application.
The only thing I can think of is if (a!=a) to test for NaN but we have
IsNan() for that.


Sure.

--
Jon Skeet - <sk***@pobox.com>
http://www.pobox.com/~skeet
If replying to the group, please do not mail me too
Nov 16 '05 #33
"cody" <pl*************************@gmx.de> wrote in
news:Og**************@TK2MSFTNGP09.phx.gbl...
...
> Who wouldn't agree with that (except the microsoft guy who decided that
> operator== for fp do not need a compiler warning).


I'm in two minds about that, personally. I can see the argument for a
warning, but at the same time it feels odd.


It may feel a bit odd but I do not think one of us ever used == on a
floating point value in a real application.
The only thing I can think of is if (a!=a) to test for NaN but we have
IsNan() for that.


That's the point I've already tried to say: I *do* use tests like "if (a
== -1) a = DoLazyCalculation();" and the like; I'd also guess the equality
operator is implicitly used when you use doubles as keys in a hashtable, or
sort an array of doubles (at least with generics, things like this should
trigger your warning, too). I don't think it would be a good idea to have a
warning *every* time the == operator is used on fp values;

BTW: If you "forbid" the == operator, wouldn't it make sense to apply the
same strictness to other comparison operators? After all, everything said
applies also to comparisons like "Math.Sqrt(2)*Math.Sqrt(2) < 2" as well.

Niki
Nov 16 '05 #34
Niki Estner <ni*********@cube.net> wrote:
It may feel a bit odd but I do not think one of us ever used == on a
floating point value in a real application.
The only thing I can think of is if (a!=a) to test for NaN but we have
IsNan() for that.
That's the point I've already tried to say: I *do* use tests like "if (a
== -1) a = DoLazyCalculation();" and the like; I'd also guess the equality
operator is implicitly used when you use doubles as keys in a hashtable, or
sort an array of doubles (at least with generics, things like this should
trigger your warning, too).


I don't think the equality operator will be used - the Equals method
will be used. There are subtle differences.
I don't think it would be a good idea to have a
warning *every* time the == operator is used on fp values;

BTW: If you "forbid" the == operator, wouldn't it make sense to apply the
same strictness to other comparison operators? After all, everything said
applies also to comparisons like "Math.Sqrt(2)*Math.Sqrt(2) < 2" as well.


Hmm... interesting point.

--
Jon Skeet - <sk***@pobox.com>
http://www.pobox.com/~skeet
If replying to the group, please do not mail me too
Nov 16 '05 #35
"Jon Skeet [C# MVP]" <sk***@pobox.com> wrote in
news:MP************************@msnews.microsoft.c om...
Niki Estner <ni*********@cube.net> wrote:
> It may feel a bit odd but I do not think one of us ever used == on a
> floating point value in a real application.
> The only thing I can think of is if (a!=a) to test for NaN but we have
> IsNan() for that.


That's the point I've already tried to say: I *do* use tests like "if (a
== -1) a = DoLazyCalculation();" and the like; I'd also guess the
equality
operator is implicitly used when you use doubles as keys in a hashtable,
or
sort an array of doubles (at least with generics, things like this should
trigger your warning, too).


I don't think the equality operator will be used - the Equals method
will be used. There are subtle differences.


Yes, you're probably right: After all, support for operators was one of the
weaknesses of .net generics. I just remembered how many compiler
errors/warnings I used to have with C++ generics if someone decided to
implement standard operators in a non-standard way...

But if "==" would issue a warning, while double.Equals would not, wouldn't
that be even more strange? After all, double.Equals will always return the
same value.

The more I think about it, the more I dislike that
"fp-equality-warning"-idea...

Niki
Nov 16 '05 #36
Niki Estner <ni*********@cube.net> wrote:

<snip other stuff>
But if "==" would issue a warning, while double.Equals would not, wouldn't
that be even more strange? After all, double.Equals will always return the
same value.


Nope - Double.Equals is different to == for NaNs. IEEE specifies that
NaN != NaN, but Object.Equals specifies that x.Equals(x) is true for
all x.

From section 8.2.5.2 of the CLI spec:

<quote>
Note: Although two floating point NaNs are defined by IEC 60559:1989 to
always compare as unequal, the contract for System.Object.Equals,
requires that overrides must satisfy the requirements for an
equivalence operator. Therefore, System.Double.Equals and
System.Single.Equals return True when comparing two NaNs, while the
equality operator returns False in that case, as required by the
standard.
</quote>

Very odd.

--
Jon Skeet - <sk***@pobox.com>
http://www.pobox.com/~skeet
If replying to the group, please do not mail me too
Nov 16 '05 #37
> That's the point I've already tried to say: I *do* use tests like "if (a
== -1) a = DoLazyCalculation();" and the like; I'd also guess the equality
operator is implicitly used when you use doubles as keys in a hashtable, or sort an array of doubles (at least with generics, things like this should
trigger your warning, too). I don't think it would be a good idea to have a warning *every* time the == operator is used on fp values;
using -1 is imho a bad idea. what if you actually need -1 in your app?
Negative numbers are very common in floating point (in contrast to
integers). What if you inadvertantly use the float variable with its -1
value?
NaN is just for that purpose: If a value is NaN it stays NaN even if used in
calculations or converted from double to float and vice versa and this way,
you know that something gone wrong if you see NaN in the output.
The following code displays 4 times NaN:

float f = float.NaN;
double d = double.NaN;
Console.WriteLine(double.IsNaN((float)d));
Console.WriteLine(double.IsNaN((double)f));
Console.WriteLine(float.IsNaN((float)d));
Console.WriteLine(float.IsNaN((float)(double)f));

The funny thing is that if you compare a float with and int value -1 the
result returns true even if its value is not -1. The following prints
"hello":

float f1 = -1.00000001f;
float f2 = -0.99999999f;
if (f1==-1 && f2==-1)
{
Console.WriteLine("hello");
}

Btw: using floating point values as hashtable keys seems to be a bad idea.
Even when flooring and ceiling values it doesn't work. The following outputs
2 times false:

float f1 = -0.99999991f;
float f2 = -0.99999999f;
float f3 = 0.99999991f;
float f4 = 0.99999999f;
Console.WriteLine(Math.Ceiling(f1)==Math.Ceiling(f 2));
Console.WriteLine(Math.Floor(f3)==Math.Floor(f4));

Only using Math.Round() seems always to work correctly.
BTW: If you "forbid" the == operator, wouldn't it make sense to apply the
same strictness to other comparison operators? After all, everything said
applies also to comparisons like "Math.Sqrt(2)*Math.Sqrt(2) < 2" as well.


Very strange I'd expect the value be smaller as 2 than bigger but it shows
that you cannot rely on exact representation. But I'd never go so far to
issue warnings on all comparison operators for floating point because it
would be simply plain stupid.

Keep in mind that if (f1 < f2) is used very commonly and works fine in
almost every situation (except the programmer makes a wrong assumtion as you
example shows), But in constrast if (f1==f2) will be undefined unless you
use *constants* for *both* values and I cannot imagine a scenario which
requires this which cannot be solved with a better method.

Whatever is said in this thread, one should never assume an exact
representation of floating point variables
even if it seems to work with some values if could fail with other ones or
fail on another platform.

--
cody

[Freeware, Games and Humor]
www.deutronium.de.vu || www.deutronium.tk
Nov 16 '05 #38
> > But if "==" would issue a warning, while double.Equals would not,
wouldn't
that be even more strange? After all, double.Equals will always return the same value.


Nope - Double.Equals is different to == for NaNs. IEEE specifies that
NaN != NaN, but Object.Equals specifies that x.Equals(x) is true for
all x.

If == isssues a warning, double.Equals() also should.

Also bare in mind that a Warning doesn't mean "It is wrong" but "It could
possibly be wrong", otherwise it would be an Error.

--
cody

[Freeware, Games and Humor]
www.deutronium.de.vu || www.deutronium.tk
Nov 16 '05 #39
"cody" <pl*************************@gmx.de> wrote in
news:e0**************@TK2MSFTNGP09.phx.gbl...
That's the point I've already tried to say: I *do* use tests like "if (a
== -1) a = DoLazyCalculation();" and the like; I'd also guess the
equality
operator is implicitly used when you use doubles as keys in a hashtable,

or
sort an array of doubles (at least with generics, things like this should
trigger your warning, too). I don't think it would be a good idea to have

a
warning *every* time the == operator is used on fp values;


using -1 is imho a bad idea. what if you actually need -1 in your app?
Negative numbers are very common in floating point (in contrast to
integers). What if you inadvertantly use the float variable with its -1
value?
NaN is just for that purpose: If a value is NaN it stays NaN even if used
in
calculations or converted from double to float and vice versa and this
way,
you know that something gone wrong if you see NaN in the output.
The following code displays 4 times NaN:


I think this is going slightly off-topic now, but of course "special values"
like these have to be values that cannot be result of a calculation.
Depending on the meaning of the value this could be a negative value (e.g
distances), NaN, a value above 100 (percentages), or whatever. Although NaN
is a good "special value", too, it does have disadvantages, sometimes: AFAIK
Double.Parse can't parse it, converting it to an int will throw an
exception, you only have one single special value, and sometimes NaN can be
result of a calculation...

Niki
Nov 16 '05 #40
"cody" <pl*************************@gmx.de> wrote in
news:%2****************@TK2MSFTNGP09.phx.gbl...
> But if "==" would issue a warning, while double.Equals would not, wouldn't > that be even more strange? After all, double.Equals will always return the > same value.


Nope - Double.Equals is different to == for NaNs. IEEE specifies that
NaN != NaN, but Object.Equals specifies that x.Equals(x) is true for
all x.

If == isssues a warning, double.Equals() also should.

Also bare in mind that a Warning doesn't mean "It is wrong" but "It could
possibly be wrong", otherwise it would be an Error.


I think that's a misunderstanding. Here are a few warnings I've randomly
picked:
CS0028 'function declaration' has the wrong signature to be an entry point
CS0105 The using directive for 'namespace' appeared previously in this
namespace
CS0162 Unreachable code detected
CS0251 Indexing an array with a negative index (array indices always start
at zero)
CS0628 'member' : new protected member declared in sealed class
CS0649 Field 'field' is never assigned to, and will always have its default
value 'value'
CS1522 Empty switch block
CS1591 Missing XML comment for publicly visible type or member
'Type_or_Member'
CS5000 Unknown compiler option '/option'

These do suggest that a warning acually means "this code can be compiled,
but it makes no sense and will either do nothing, or crash". I don't think a
fp comparison would fit in that category.

Niki
Nov 16 '05 #41
cody <pl*************************@gmx.de> wrote:
The funny thing is that if you compare a float with and int value -1 the
result returns true even if its value is not -1. The following prints
"hello":

float f1 = -1.00000001f;
float f2 = -0.99999999f;
if (f1==-1 && f2==-1)
{
Console.WriteLine("hello");
}


There's nothing funny about that - the nearest float to those literals
is exactly -1. Have a look in the IL. That explains the Ceiling/Floor
problems you were having too.

--
Jon Skeet - <sk***@pobox.com>
http://www.pobox.com/~skeet
If replying to the group, please do not mail me too
Nov 16 '05 #42
> >> That's the point I've already tried to say: I *do* use tests like "if
(a
== -1) a = DoLazyCalculation();" and the like; I'd also guess the
equality
operator is implicitly used when you use doubles as keys in a hashtable,
or
sort an array of doubles (at least with generics, things like this
should trigger your warning, too). I don't think it would be a good idea to
have a
warning *every* time the == operator is used on fp values;


using -1 is imho a bad idea. what if you actually need -1 in your app?
Negative numbers are very common in floating point (in contrast to
integers). What if you inadvertantly use the float variable with its -1
value?
NaN is just for that purpose: If a value is NaN it stays NaN even if used in
calculations or converted from double to float and vice versa and this
way,
you know that something gone wrong if you see NaN in the output.
The following code displays 4 times NaN:


I think this is going slightly off-topic now, but of course "special

values" like these have to be values that cannot be result of a calculation.
Depending on the meaning of the value this could be a negative value (e.g
distances), NaN, a value above 100 (percentages), or whatever. Although NaN is a good "special value", too, it does have disadvantages, sometimes: AFAIK Double.Parse can't parse it, converting it to an int will throw an
exception,
If you use it as special value to mean "uninitialized", you certainly won't
parse it or convert it to int.
you only have one single special value,
otherwise it wouldn't be special :)
and sometimes NaN can be result of a calculation...


Indeed, NaN can be result of a calculation whereas -1 can't :)))

In fact, special values(besides NaN,NegativeInf,PositiveInf) in floating
point sounds a bit like an oxymoron (ok it isn't). But maybe special ranges
are ok.

--
cody

[Freeware, Games and Humor]
www.deutronium.de.vu || www.deutronium.tk
Nov 16 '05 #43
> > float f1 = -1.00000001f;
float f2 = -0.99999999f;
if (f1==-1 && f2==-1)
{
Console.WriteLine("hello");
}


There's nothing funny about that - the nearest float to those literals
is exactly -1. Have a look in the IL. That explains the Ceiling/Floor
problems you were having too.

I'd have expected a simple truncation which would have returned true for
f1==-1 but false for f2==-1,
since -0.999999f would have been truncated to 0 which obviously wasn't the
case. And who guarantees that every platform will handle this the same way?
Even if the standard exactly dictates what should happen such edge cases are
imho always a good candidate for implementation errors.

I stick to my opinion - never trust a floating point value.

--
cody

[Freeware, Games and Humor]
www.deutronium.de.vu || www.deutronium.tk
Nov 16 '05 #44
cody <pl*************************@gmx.de> wrote:
float f1 = -1.00000001f;
float f2 = -0.99999999f;
if (f1==-1 && f2==-1)
{
Console.WriteLine("hello");
}
There's nothing funny about that - the nearest float to those literals
is exactly -1. Have a look in the IL. That explains the Ceiling/Floor
problems you were having too.


I'd have expected a simple truncation which would have returned true for
f1==-1 but false for f2==-1,
since -0.999999f would have been truncated to 0 which obviously wasn't the
case.


No - both f1 and f2 are exactly -1.
And who guarantees that every platform will handle this the same way?
The C# specification states:

<quote>
The value of a real literal having type float or double is determined
by using the IEEE "round to nearest" mode.
</quote>

I have no reason to doubt that applying that to both -1.00000001 and
-0.99999999 would show that both should have a value of -1.
Even if the standard exactly dictates what should happen such edge
cases are imho always a good candidate for implementation errors.

I stick to my opinion - never trust a floating point value.


Well, only trust a floating point value if you know what's going on. My
point is that there was nothing "funny" going on in your code - it was
perfectly predictable.

--
Jon Skeet - <sk***@pobox.com>
http://www.pobox.com/~skeet
If replying to the group, please do not mail me too
Nov 16 '05 #45

This thread has been closed and replies have been disabled. Please start a new discussion.

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.