Why? All we know it that both are not-numbers. It's just a label for something that cannot usefully be further identified.
I'm pretty sure mathematicians can come up with many different not-numbers that have to share the same label, with a rather slim chance of being equal ...
They don't have to share the same label. 64 bit floating points have 2^52 different NaN values. Even Float16 has 1024 which should be more than enough for all the indeterminent forms.
Collisions will come up. If you have some allocator for NaN, it will have to start reusing values. The allocator could be inefficient. How do you handle threads? Does each thread have its own NaN-allocating counter? What if threads communicate numeric results to each other and have NaN-counters close in value?
The underlying problem is that a system of calculation which propagates error symbols up the expression tree to indicate error is mixed with a system of Boolean calculation which has no such symbol. The bad calculation bubbles up a NaN up to the level of the comparison. There, the not-a-number gets eaten and becomes a Boolean true or false --- rather than becoming not-a-truth and continuing to bubble up.
There is no satisfactory way to plug NaNs into an expression that produces a clean two-valued Boolean truth with no error indication. You must separately test for the NaN.
If X and Y are the same label, they should compare equal to satisfy the Law of Identity.
If you perform two calculations, whose values are coming up as equal, but you didn't check the fact that both calculated the same NaN, that is your problem.
Suppose you are looking for the result of the two calculations being unequal, and they produce NaN (or at least one of them does). That's also false positive. There is no way to get around checking for NaN.
Nothing which cheerfully concludes that two bitwise-identical operands are different can be called equality.
The equality operation should only apply its own specific logic to a pair of operands which fail the bitwise test.
(That doesn't mean all bits have to be looked at, like if an object has padding bits that don't contribute to the value.)
In floating-point, like IEE754, a positive and negative zero still compare equal; they failed the bitwise test, so then the numeric logic still concludes they are the same number.
Nothing which cheerfully concludes that two bitwise-identical operands are different can be called equality.
You are asserting that as if it were some kind of law of nature, but I'm afraid that's just your personal misconception. The IEEE754 equality function is defined such that it can sometimes be false when applied to identical operands. There are very good reasons why that is the case, just like there are very good reasons why NULL = NULL is false in SQL.
See upthread: law of identity. That's even higher than nature.
The IEEE754 equality function is defined such that it can sometimes be false when applied to identical operands.
Cool! So, OK, (1) don't promote that function into the fundamental equality operator of programming languages; put it in a library. (2) provide a real equality in parallel.
I should be able to do things like this:
double x = find_number_in_list(list, number, not_found_nan);
if (x == not_found_nan) { /* wasn't found */ }
I see you are referring to "identical operands"; that requires the intellectual basis of an identity relation under entities are identical to themselves. Otherwise there is no foundation for your sentence.
We can have all sorts of weird functions whose properties are useful insofar that they remove complexity or verbosity from specific scenarios in which they are used.
For instance, it's useful to have a numeric equality operator which tests that two values are within a small epsilon of each other and reports true. That's not even an equivalence relation though; near(A, B) and near(B, C) does not imply near(A, C).
It would be pretty irresponsible to put this behavior into the principal equality, like the one and only built-in == operator of a language or what have you.
there are very good reasons why NULL = NULL is false in SQL.
I don't know much about SQL, but I understand why, in a join of two tables based on some field equivalence, you wouldn't want to include the entries where the fields are NULL.
However, there is no conflict here with the Law of Identity.
In a database, a NULL field is an external representation stored in a table. We can define a model of computation whereby when the database record is internalized for processing, each NULL field value maps to a unique object. This is very similar to the concept of an uninterned symbol in Common Lisp:
(eq '#:null '#:null) -> NIL
The #: syntax, whenever scanned, creates a new symbol object. There are two different objects in the above eq call which only look the same when printed, because they have the same name. This idea could be used to implement null database field values.
However, we can retain the idea that if we pull a null value from a specific field from a specific record, that null value is equal to itself. We do not have to throw the Law of Identity under the bus, in other words:
(let ((sym '#:null)) (eq sym sym)) -> T
If we do the following in SQL (pardon me if I don't have the syntax right), I expect the table to be replicated in the selection:
select * from X where X.Y == X.Y
records where Y is NULL should not be missing. If A and B are different records in this X table, such that A.Y and B.Y are NULL, then A.Y == B.Y can be false; that is perfectly okay.
No one was talking about bitwise equality though. Bitwise equality means positive and negative zero do not compare as equal, and some NaNs compare as equal while others don't, in ways that will vary according to exactly where those NaNs came from. There may be times where that might be useful but it would be uncommon.
Comments
Why? All we know it that both are not-numbers. It's just a label for something that cannot usefully be further identified.
I'm pretty sure mathematicians can come up with many different not-numbers that have to share the same label, with a rather slim chance of being equal ...
They don't have to share the same label. 64 bit floating points have 2^52 different NaN values. Even Float16 has 1024 which should be more than enough for all the indeterminent forms.
Collisions will come up. If you have some allocator for NaN, it will have to start reusing values. The allocator could be inefficient. How do you handle threads? Does each thread have its own NaN-allocating counter? What if threads communicate numeric results to each other and have NaN-counters close in value?
The underlying problem is that a system of calculation which propagates error symbols up the expression tree to indicate error is mixed with a system of Boolean calculation which has no such symbol. The bad calculation bubbles up a NaN up to the level of the comparison. There, the not-a-number gets eaten and becomes a Boolean true or false --- rather than becoming not-a-truth and continuing to bubble up.
There is no satisfactory way to plug NaNs into an expression that produces a clean two-valued Boolean truth with no error indication. You must separately test for the NaN.
If X and Y are the same label, they should compare equal to satisfy the Law of Identity.
If you perform two calculations, whose values are coming up as equal, but you didn't check the fact that both calculated the same NaN, that is your problem.
Suppose you are looking for the result of the two calculations being unequal, and they produce NaN (or at least one of them does). That's also false positive. There is no way to get around checking for NaN.
Numeric equality is not the same as bitwise equality. Use the right operation for your intention.
Nothing which cheerfully concludes that two bitwise-identical operands are different can be called equality.
The equality operation should only apply its own specific logic to a pair of operands which fail the bitwise test.
(That doesn't mean all bits have to be looked at, like if an object has padding bits that don't contribute to the value.)
In floating-point, like IEE754, a positive and negative zero still compare equal; they failed the bitwise test, so then the numeric logic still concludes they are the same number.
You are asserting that as if it were some kind of law of nature, but I'm afraid that's just your personal misconception. The IEEE754 equality function is defined such that it can sometimes be false when applied to identical operands. There are very good reasons why that is the case, just like there are very good reasons why NULL = NULL is false in SQL.
See upthread: law of identity. That's even higher than nature.
Cool! So, OK, (1) don't promote that function into the fundamental equality operator of programming languages; put it in a library. (2) provide a real equality in parallel.
I should be able to do things like this:
I see you are referring to "identical operands"; that requires the intellectual basis of an identity relation under entities are identical to themselves. Otherwise there is no foundation for your sentence.We can have all sorts of weird functions whose properties are useful insofar that they remove complexity or verbosity from specific scenarios in which they are used.
For instance, it's useful to have a numeric equality operator which tests that two values are within a small epsilon of each other and reports true. That's not even an equivalence relation though; near(A, B) and near(B, C) does not imply near(A, C).
It would be pretty irresponsible to put this behavior into the principal equality, like the one and only built-in == operator of a language or what have you.
I don't know much about SQL, but I understand why, in a join of two tables based on some field equivalence, you wouldn't want to include the entries where the fields are NULL.
However, there is no conflict here with the Law of Identity.
In a database, a NULL field is an external representation stored in a table. We can define a model of computation whereby when the database record is internalized for processing, each NULL field value maps to a unique object. This is very similar to the concept of an uninterned symbol in Common Lisp:
The #: syntax, whenever scanned, creates a new symbol object. There are two different objects in the above eq call which only look the same when printed, because they have the same name. This idea could be used to implement null database field values.However, we can retain the idea that if we pull a null value from a specific field from a specific record, that null value is equal to itself. We do not have to throw the Law of Identity under the bus, in other words:
If we do the following in SQL (pardon me if I don't have the syntax right), I expect the table to be replicated in the selection: records where Y is NULL should not be missing. If A and B are different records in this X table, such that A.Y and B.Y are NULL, then A.Y == B.Y can be false; that is perfectly okay.No one was talking about bitwise equality though. Bitwise equality means positive and negative zero do not compare as equal, and some NaNs compare as equal while others don't, in ways that will vary according to exactly where those NaNs came from. There may be times where that might be useful but it would be uncommon.