doubles a == b or not ?
-
Is there anything that specifies that two NaN's will test equal to each other via the .Equals predicate? I recall one floating-point system where the bit value of a NaN would indicate which type of operation first produced an invalid value, so sqrt(-1) would yield one bit pattern while (0/0) would yield another. I would expect that if a variable holding a NaN is copied to another variable of the same precision, the two variables would be guaranteed to compare .Equals, but that wouldn't imply that all NaN's are equal. Do you know what actual rules exist?
Yes - here are the rules laid out by the ECMA CLI standard. For ==:
3.21 ceq
The ceq instruction compares value1 and value2. If value1 is equal to value2, then 1 (of
type int32) is pushed on the stack. Otherwise, 0 (of type int32) is pushed on the stack.
For floating-point numbers, ceq will return 0 if the numbers are unordered (either or both
are NaN). The infinite values are equal to themselves.For Object.Equals(Object):
8.2.5.2 Equality
For value types, the equality operator is part of the definition of the exact type.
Definitions of equality should obey the following rules:• Equality should be an equivalence operator, as defined above.
• Identity should imply equality, as stated earlier.
• If either (or both) operand is a boxed value, equality should be computed by
o first unboxing any boxed operand(s), and then
o applying the usual rules for equality on the resulting values.Equality is implemented on System.Object via the Equals method.
[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 IEC standard. end note]Unfortunately, as far as bit patterns are concerned with NaN... things get much more vague. It's good in some sense because it means you don't really have to deal with it on the bit pattern level, though. As long as you stay within a precision, you can pretty safely assume NaN is NaN in .NET.:
12.1.3 Handling of floating-point data types
Floating-point calculations shall be handled as described in IEC 60559:1989. This standard
describes encoding of floating-point numbers, definitions of the basic operations and
conversion, rounding control, and exception handling.The standard defines special values, NaN, (not a number), +infinity, and –infinity. These
values are returned on overflow conditions. A general principle is that operations that
have a value in the limit return an appropriate infinity while those that have no limiting
value return NaN (see the standard for details).[Note: The following examples show the most commonly encountered cases.
X rem 0 = NaN
0 * +infinity = 0 * -infinity = NaN
(X / 0) = +infinity, if X > 0
NaN, if X = 0
infinity, if X < 0
NaN op X = X op -
Yes - here are the rules laid out by the ECMA CLI standard. For ==:
3.21 ceq
The ceq instruction compares value1 and value2. If value1 is equal to value2, then 1 (of
type int32) is pushed on the stack. Otherwise, 0 (of type int32) is pushed on the stack.
For floating-point numbers, ceq will return 0 if the numbers are unordered (either or both
are NaN). The infinite values are equal to themselves.For Object.Equals(Object):
8.2.5.2 Equality
For value types, the equality operator is part of the definition of the exact type.
Definitions of equality should obey the following rules:• Equality should be an equivalence operator, as defined above.
• Identity should imply equality, as stated earlier.
• If either (or both) operand is a boxed value, equality should be computed by
o first unboxing any boxed operand(s), and then
o applying the usual rules for equality on the resulting values.Equality is implemented on System.Object via the Equals method.
[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 IEC standard. end note]Unfortunately, as far as bit patterns are concerned with NaN... things get much more vague. It's good in some sense because it means you don't really have to deal with it on the bit pattern level, though. As long as you stay within a precision, you can pretty safely assume NaN is NaN in .NET.:
12.1.3 Handling of floating-point data types
Floating-point calculations shall be handled as described in IEC 60559:1989. This standard
describes encoding of floating-point numbers, definitions of the basic operations and
conversion, rounding control, and exception handling.The standard defines special values, NaN, (not a number), +infinity, and –infinity. These
values are returned on overflow conditions. A general principle is that operations that
have a value in the limit return an appropriate infinity while those that have no limiting
value return NaN (see the standard for details).[Note: The following examples show the most commonly encountered cases.
X rem 0 = NaN
0 * +infinity = 0 * -infinity = NaN
(X / 0) = +infinity, if X > 0
NaN, if X = 0
infinity, if X < 0
NaN op X = X opGood info, but when pasting docs into a pre block you really need to insert manual linebreaks. That's going to horizontal scroll on anything less than a dual 30" setup.
Today's lesson is brought to you by the word "niggardly". Remember kids, don't attribute to racism what can be explained by Scandinavian language roots. -- Robert Royall
-
Good info, but when pasting docs into a pre block you really need to insert manual linebreaks. That's going to horizontal scroll on anything less than a dual 30" setup.
Today's lesson is brought to you by the word "niggardly". Remember kids, don't attribute to racism what can be explained by Scandinavian language roots. -- Robert Royall
-
How often is the handling of infinity and negative infinity actually useful? If x is the largest non-infinite positive float, the expression x+x+(-x)+(-x) could evaluate as positive infinity, negative infinity, zero, or NaN, depending upon the order of evaluation. In what sense would any value other than zero or NaN be meaningful?
SHouldn't it end up as NaN no matter what execution order is?
-
SHouldn't it end up as NaN no matter what execution order is?
peterchen wrote:
SHouldn't it end up as NaN no matter what execution order is?
The expression I gave was x+x+(-x)+(-x). (((x+x)-x)-x) should yield positive infinity (inf-x is inf) (x+(x-(x+x))) should yield negative infinity (-inf+x is -inf) (x+x)-(x+x) should yield NaN (inf + -inf is NaN) x+(x-x)-x should yield zero (no overflows anyplace).
-
Never... well virtually never, a wise developer would never trust it.
A wise developer would never compare a double or float for equality without washing the data first.
"Why don't you tie a kerosene-soaked rag around your ankles so the ants won't climb up and eat your candy ass..." - Dale Earnhardt, 1997
-----
"...the staggering layers of obscenity in your statement make it a work of art on so many levels." - Jason Jystad, 10/26/2001 -
peterchen wrote:
SHouldn't it end up as NaN no matter what execution order is?
The expression I gave was x+x+(-x)+(-x). (((x+x)-x)-x) should yield positive infinity (inf-x is inf) (x+(x-(x+x))) should yield negative infinity (-inf+x is -inf) (x+x)-(x+x) should yield NaN (inf + -inf is NaN) x+(x-x)-x should yield zero (no overflows anyplace).
I am not sure how IEEE floats work, but inf-x=inf works only for finite x. inf-inf should in any case end up
NaN
, and no matter how this expression is evaluated, you will end up with that subexpression at one point, and once any operand is NaN, it should stick.
I googled, here's what I came upon: scroll down to "special operations": Clickety[^]
-
I am not sure how IEEE floats work, but inf-x=inf works only for finite x. inf-inf should in any case end up
NaN
, and no matter how this expression is evaluated, you will end up with that subexpression at one point, and once any operand is NaN, it should stick.
I googled, here's what I came upon: scroll down to "special operations": Clickety[^]
I should have said that the indicated mathematical expression could yield four different results depending upon the order in which the terms were grouped. If the expression is coded in a particular form, the language's standard rules of associativity will dictate how the terms are grouped, but if it is computed using something like a sum() method on a database field, such behavior would not be guaranteed. While it wouldn't seem particularly likely that an implementation would separately sum together the two positive terms and the two negative terms before adding the two sums, such an approach would generally yield better precision than adding everything in sequence.
-
I should have said that the indicated mathematical expression could yield four different results depending upon the order in which the terms were grouped. If the expression is coded in a particular form, the language's standard rules of associativity will dictate how the terms are grouped, but if it is computed using something like a sum() method on a database field, such behavior would not be guaranteed. While it wouldn't seem particularly likely that an implementation would separately sum together the two positive terms and the two negative terms before adding the two sums, such an approach would generally yield better precision than adding everything in sequence.
My point was that grouping doesn't matter if you define the arithmetics for special values correctly (Which the IEEE standard apparently does)
-
My point was that grouping doesn't matter if you define the arithmetics for special values correctly (Which the IEEE standard apparently does)
Grouping very much does matter. Adding together the four items: +x, +x, -x, -x (where x is the the largest number short of infinity) If they are grouped as (+x + +x) + (-x + -x) the result will be (+inf) + (-inf), or NaN. If they are grouped as ((+x + +x) + -x) + -x the result will be (+inf + -x) + -x, or +inf + -x, or +inf. If they are grouped as +x + (+x + (-x + -x)) the result will be +x + (+x + -inf), or +x + -inf, or -inf. If they are grouped as (+x + (+x + -x)) + -x, the result will be (+x + 0) + -x, or +x + -x, or zero. With which of those statements do you disagree.
-
Grouping very much does matter. Adding together the four items: +x, +x, -x, -x (where x is the the largest number short of infinity) If they are grouped as (+x + +x) + (-x + -x) the result will be (+inf) + (-inf), or NaN. If they are grouped as ((+x + +x) + -x) + -x the result will be (+inf + -x) + -x, or +inf + -x, or +inf. If they are grouped as +x + (+x + (-x + -x)) the result will be +x + (+x + -inf), or +x + -inf, or -inf. If they are grouped as (+x + (+x + -x)) + -x, the result will be (+x + 0) + -x, or +x + -x, or zero. With which of those statements do you disagree.
supercat9 wrote:
largest number short of infinity
ohhh... I missed that all the time :sigh:
-
supercat9 wrote:
largest number short of infinity
ohhh... I missed that all the time :sigh:
-
Correct, nice job. :) Basically, the IEEE definition of equality for floating points requires NaN != NaN (see here)... but the .NET definition of equality requires that a.Equals(a). (Otherwise, you'd never be able to get anything back out of a Dictionary if the key had a NaN in it). So floats and doubles have a special clause in their Equals operator that checks for NaN for this reason.
akidan wrote:
the .NET definition of equality requires that a.Equals(a). (Otherwise, you'd never be able to get anything back out of a Dictionary if the key had a NaN in it
And that would be a problem? Whoever sticks a NaN into a dictionary deserves to not get the values back! NaN is defined as "This is a marker for overflow somewhere. It is not comparable with anything."
Let's think the unthinkable, let's do the undoable, let's prepare to grapple with the ineffable itself, and see if we may not eff it after all.
Douglas Adams, "Dirk Gently's Holistic Detective Agency" -
akidan wrote:
the .NET definition of equality requires that a.Equals(a). (Otherwise, you'd never be able to get anything back out of a Dictionary if the key had a NaN in it
And that would be a problem? Whoever sticks a NaN into a dictionary deserves to not get the values back! NaN is defined as "This is a marker for overflow somewhere. It is not comparable with anything."
Let's think the unthinkable, let's do the undoable, let's prepare to grapple with the ineffable itself, and see if we may not eff it after all.
Douglas Adams, "Dirk Gently's Holistic Detective Agency"Now if you keep adding all kinds of NaNs to a dictionary, it will overflow too. :)
Luc Pattyn [Forum Guidelines] [My Articles]
- before you ask a question here, search CodeProject, then Google - the quality and detail of your question reflects on the effectiveness of the help you are likely to get - use the code block button (PRE tags) to preserve formatting when showing multi-line code snippets
-
akidan wrote:
the .NET definition of equality requires that a.Equals(a). (Otherwise, you'd never be able to get anything back out of a Dictionary if the key had a NaN in it
And that would be a problem? Whoever sticks a NaN into a dictionary deserves to not get the values back! NaN is defined as "This is a marker for overflow somewhere. It is not comparable with anything."
Let's think the unthinkable, let's do the undoable, let's prepare to grapple with the ineffable itself, and see if we may not eff it after all.
Douglas Adams, "Dirk Gently's Holistic Detective Agency"Part of having a unified type system means that there is no difference between float64-the-primitive and System.Double-the-object - they must be treated as one and the same. However, now you have a contradiction. The definition of equality for floating point numbers is fundamentally incompatible with the contract for equality of objects in .NET. Floating point requires that NaN must not equal NaN. System.Object requires that a.Equals(a) returns true. If you make a special exception for the a.Equals(a) rule for doubles and floats, you have now broken the contract of equality for objects and thus broken polymorphism. One can no longer write code under the assumption that a.Equals(a) always holds true.
-
Part of having a unified type system means that there is no difference between float64-the-primitive and System.Double-the-object - they must be treated as one and the same. However, now you have a contradiction. The definition of equality for floating point numbers is fundamentally incompatible with the contract for equality of objects in .NET. Floating point requires that NaN must not equal NaN. System.Object requires that a.Equals(a) returns true. If you make a special exception for the a.Equals(a) rule for doubles and floats, you have now broken the contract of equality for objects and thus broken polymorphism. One can no longer write code under the assumption that a.Equals(a) always holds true.
akidan wrote:
If you make a special exception for the a.Equals(a) rule for doubles and floats, you have now broken the contract of equality for objects
Sure. And this way, you have broken the contract of IEEE math. And guess what's older... But I admit - you are to die one death, and .NET choose to violate the math rules.
Let's think the unthinkable, let's do the undoable, let's prepare to grapple with the ineffable itself, and see if we may not eff it after all.
Douglas Adams, "Dirk Gently's Holistic Detective Agency" -
akidan wrote:
If you make a special exception for the a.Equals(a) rule for doubles and floats, you have now broken the contract of equality for objects
Sure. And this way, you have broken the contract of IEEE math. And guess what's older... But I admit - you are to die one death, and .NET choose to violate the math rules.
Let's think the unthinkable, let's do the undoable, let's prepare to grapple with the ineffable itself, and see if we may not eff it after all.
Douglas Adams, "Dirk Gently's Holistic Detective Agency" -
A wise developer would never compare a double or float for equality without washing the data first.
"Why don't you tie a kerosene-soaked rag around your ankles so the ants won't climb up and eat your candy ass..." - Dale Earnhardt, 1997
-----
"...the staggering layers of obscenity in your statement make it a work of art on so many levels." - Jason Jystad, 10/26/2001A wise developer uses only
int
s. :)If the Lord God Almighty had consulted me before embarking upon the Creation, I would have recommended something simpler. -- Alfonso the Wise, 13th Century King of Castile.
This is going on my arrogant assumptions. You may have a superb reason why I'm completely wrong. -- Iain Clarke
[My articles] -
Well, actually this is not really a bug, but a very strange behavior of the .NET double type. I'll put it as a riddle and let you find it out ! Ok, if no one found it, I'll post the answer, over a couple of days, time to let you search... ;) Take the following method:
public static string LittleTest(double a, double b)
{
double x = 5.0;if (a != b) return "Try other values for a and b..."; double xa = x / a; double xb = x / b; if (xa == xb) return "Not yet right..."; else return "You've got it !!!";
}
For which values a and b will the method return "You've got it !!!" ???
I'm tempted to use the Decimal type whenever I can to make results more predictable.
So the creationist says: Everything must have a designer. God designed everything. I say: Why is God the only exception? Why not make the "designs" (like man) exceptions and make God a creation of man?
-
What is negative zero?:confused: