February 07, 2009
Bill Baxter wrote:
> Note that D already has things like !>.   But quoth the spec:
> "For floating point comparison operators, (a !op b)  is *NOT* the same
> as !(a op b)."
> [emphasis added]

I had to check the spec for the difference.  'a !< b' and '!(a < b)'
/are/ equivalent in the sense that '(a !< b) == !(a < b)' for any values
of 'a' and 'b'.  The vast majority of the time, the expressions 'a !< b'
and '!(a < b)' /are/ interchangeable.  The difference is that '!(a < b)'
sets a global exception state if either operand is NaN, while 'a !< b'
does not.

This is, in my opinion, a significant design error in the language.  The difference between '!(a < b)' and 'a !< b' is not obvious.  There is nothing about the operator '<' that suggests that it should set a global exception state, and there is nothing about '!<' that suggests that it should /not/ set a global exception state.  (Is global state for error reporting ever a good idea in a high-level language?)  It also adds awkward expressions to the language, not just in the form '!(a < b)', but in the form '!(a !< b)'.


-- 
Rainer Deyke - rainerd@eldwood.com
February 07, 2009

Rainer Deyke wrote:
> Bill Baxter wrote:
>> Note that D already has things like !>.   But quoth the spec:
>> "For floating point comparison operators, (a !op b)  is *NOT* the same
>> as !(a op b)."
>> [emphasis added]
> 
> I had to check the spec for the difference.  'a !< b' and '!(a < b)'
> /are/ equivalent in the sense that '(a !< b) == !(a < b)' for any values
> of 'a' and 'b'.  The vast majority of the time, the expressions 'a !< b'
> and '!(a < b)' /are/ interchangeable.  The difference is that '!(a < b)'
> sets a global exception state if either operand is NaN, while 'a !< b'
> does not.
> 
> This is, in my opinion, a significant design error in the language.  The difference between '!(a < b)' and 'a !< b' is not obvious.  There is nothing about the operator '<' that suggests that it should set a global exception state, and there is nothing about '!<' that suggests that it should /not/ set a global exception state.  (Is global state for error reporting ever a good idea in a high-level language?)  It also adds awkward expressions to the language, not just in the form '!(a < b)', but in the form '!(a !< b)'.

I believe this is, or is the result of, an aspect of IEEE floating point.

  -- Daniel
February 07, 2009
Daniel Keep wrote:
> 
> Rainer Deyke wrote:
>> Bill Baxter wrote:
>>> Note that D already has things like !>.   But quoth the spec:
>>> "For floating point comparison operators, (a !op b)  is *NOT* the same
>>> as !(a op b)."
>>> [emphasis added]
>> I had to check the spec for the difference.  'a !< b' and '!(a < b)'
>> /are/ equivalent in the sense that '(a !< b) == !(a < b)' for any values
>> of 'a' and 'b'.  The vast majority of the time, the expressions 'a !< b'
>> and '!(a < b)' /are/ interchangeable.  The difference is that '!(a < b)'
>> sets a global exception state if either operand is NaN, while 'a !< b'
>> does not.
>>
>> This is, in my opinion, a significant design error in the language.  The
>> difference between '!(a < b)' and 'a !< b' is not obvious.  There is
>> nothing about the operator '<' that suggests that it should set a global
>> exception state, and there is nothing about '!<' that suggests that it
>> should /not/ set a global exception state.  (Is global state for error
>> reporting ever a good idea in a high-level language?)  It also adds
>> awkward expressions to the language, not just in the form '!(a < b)',
>> but in the form '!(a !< b)'.
> 
> I believe this is, or is the result of, an aspect of IEEE floating point.
> 
>   -- Daniel

Yes. It's the hardware. It's hard to find situations where the difference matters.  And this is why !<> and !<>= are the only ones of those operators which are actually useful.
February 07, 2009
Daniel Keep wrote:
> Rainer Deyke wrote:
>> This is, in my opinion, a significant design error in the language.  The difference between '!(a < b)' and 'a !< b' is not obvious.  There is nothing about the operator '<' that suggests that it should set a global exception state, and there is nothing about '!<' that suggests that it should /not/ set a global exception state.  (Is global state for error reporting ever a good idea in a high-level language?)  It also adds awkward expressions to the language, not just in the form '!(a < b)', but in the form '!(a !< b)'.
> 
> I believe this is, or is the result of, an aspect of IEEE floating point.

I don't have a copy of the IEEE floating point standard, but I strongly
suspect it would have allowed syntax like:
  a < b // sets global state
  a !< b // sets global state
  less_than_no_state(a, b) // does not set global state
  !less_than_no_state(a, b) // does not set global state
Or:
  a < b // does not set global state
  a !< b // does not set global state
  less_than_set_state(a, b) // sets global state
  !less_than_set_state(a, b) // sets global state
Or:
  a < b // sets global state
  a !< b // sets global state
  a [<] b // does not set global state
  a [!<] b // does not set global state
Or any number of other syntax choices, all less confusing than the
syntax actually used.

This is assuming we need two sets of comparison operators, one of which uses global state to report NaN operands and one which does not.  I'm not convinced that this is the case.


-- 
Rainer Deyke - rainerd@eldwood.com
February 07, 2009
Rainer Deyke wrote:
> Daniel Keep wrote:
>> Rainer Deyke wrote:
>>> This is, in my opinion, a significant design error in the language.  The
>>> difference between '!(a < b)' and 'a !< b' is not obvious.  There is
>>> nothing about the operator '<' that suggests that it should set a global
>>> exception state, and there is nothing about '!<' that suggests that it
>>> should /not/ set a global exception state.  (Is global state for error
>>> reporting ever a good idea in a high-level language?)  It also adds
>>> awkward expressions to the language, not just in the form '!(a < b)',
>>> but in the form '!(a !< b)'.
>> I believe this is, or is the result of, an aspect of IEEE floating point.
> 
> I don't have a copy of the IEEE floating point standard, but I strongly
> suspect it would have allowed syntax like:
>   a < b // sets global state
>   a !< b // sets global state
>   less_than_no_state(a, b) // does not set global state
>   !less_than_no_state(a, b) // does not set global state
> Or:
>   a < b // does not set global state
>   a !< b // does not set global state
>   less_than_set_state(a, b) // sets global state
>   !less_than_set_state(a, b) // sets global state
> Or:
>   a < b // sets global state
>   a !< b // sets global state
>   a [<] b // does not set global state
>   a [!<] b // does not set global state
> Or any number of other syntax choices, all less confusing than the
> syntax actually used.
> 
> This is assuming we need two sets of comparison operators, one of which
> uses global state to report NaN operands and one which does not.  I'm
> not convinced that this is the case.

I don't have the final standard, but the last publically avilable draft (IEE754R Draft 1.2.5, Oct 2006) states:

"The unordered-signaling predicates in Table 9, intended for use by programs not written to take into account
the possibility of NaN operands, signal an invalid exception on quiet NaN operands:" [table 9]
"The unordered-quiet predicates in Table 10, intended for use by programs written to take into account the
possibility of NaN operands, do not signal an exception on quiet NaN operands:" [table 10]

"There are two ways to write the logical negation of a predicate, one using NOT explicitly and the other
reversing the relational operator. Thus in programs written without considering the possibility of a NaN
operand, the logical negation of the unordered-signaling predicate (X < Y) is just the unordered-signaling
predicate NOT(X < Y); the unordered-quiet reversed predicate (X ?>= Y) is different in that it does not signal
an invalid operation exception when X and Y are unordered. In contrast, the logical negation of (X = Y) may
be written either NOT(X = Y) or (X ?<> Y); in this case both expressions are functionally equivalent to (X != Y).

The "global state" you're referring to is just a flag in the floating-point status register.

Although I believe you could implement these comparisons as functions rather than operators, they'd have to be intrinsics. On x87, the normal comparisons are done with the FCOM instruction, and the others are done with FCOMI. That's the only difference.
February 07, 2009
Bill Baxter wrote:
> On Sat, Feb 7, 2009 at 8:54 AM, bearophile <bearophileHUGS@lycos.com> wrote:
>> Rainer Deyke:
>>> It's a question of consistent patterns versus special cases.
>> You may think that for humans it's better to have a very orthogonal language, like for example Scheme.
>> There's also a famous quote about this, "Programming languages should be designed not by piling feature on top of feature, but by removing the weaknesses and restrictions that make additional features appear necessary." But in practice the large part of programmers work with languages like Java, C, C++, C#, Python, modern basic variants, etc despite they have much more restrictions compared to Scheme.
>> This is a long thing to explain, and I don't have enough space in this tight post to explain it, but the short version is that removing "special cases" as allowing !+ makes the language worse, less easy to use, more bug-prone, and generally less good.
> 
> Note that D already has things like !>.

Well yeah, but note that it can be pronounced "not bigger", as opposed to !+.
February 08, 2009
On Sat, 07 Feb 2009 00:39:33 +0100, Rainer Deyke <rainerd@eldwood.com> wrote:

> (Of course '!=' (as the opposite of '==' as opposed to '=') is already a
> special case, so perhaps defining the '!<op>' operators individually is
> unavoidable.  'a !== b' as '!(a == b)' would work, but 'a != b' as '!(a
> = b)' would be very weird and inconsistent with other languages.)

From the identity (a != b) == !(a == b), you could argue that
(a !<op> b) == !(a <op>= b), but I can hardly see that being better. :p


--
Simen
1 2
Next ›   Last »