Boost logo

Boost :

Subject: Re: [boost] [ICL] #6853: boost::icl::contains(NaN) returns true
From: Joachim Faulhaber (afojgo_at_[hidden])
Date: 2012-05-13 11:37:55


2012/5/9 Paul A. Bristow <pbristow_at_[hidden]>:
>
>
>> -----Original Message-----
>> From: boost-bounces_at_[hidden] [mailto:boost-bounces_at_[hidden]] On Behalf Of Joachim
>> Faulhaber
>> Sent: Wednesday, May 09, 2012 3:32 PM
>> To: boost_at_[hidden]
>> Subject: Re: [boost] [ICL] #6853: boost::icl::contains(NaN) returns true
>>
>> 2012/5/9 Paul A. Bristow <pbristow_at_[hidden]>:
>> >
>> >> 2012/5/8 Joachim Faulhaber <afojgo_at_[hidden]>:
>> >> >
>> >> > I don't think the ICL should support NaN. Moreover I believe boost
>> >> > libraries and generic concepts should not integrate NaN in general.
>> >> > In a way I conceive NaN as being "anti generic". Wherever I run
>> >> > into the NaN phenomenon, it tends to jeopardize simplicity and
>> >> > elegance in generic designs.
>> >>
>> >>
>> >> NaNtheLess! I found a generic solution to the problem :)
>> >>
>> >> template<class Float>
>> >> struct NaNtheLess
>> >> {
>> >>     bool operator()(Float lhs, Float rhs)const
>> >>     {
>> >>         return tr1::isnan(lhs)
>> >>                     ? !tr1::isnan(rhs)
>> >>                     : std::less<Float>()(lhs, rhs);
>> >>     }
>> >> };
>> >>
>> >>
>> >> Hope this solves your problems. NaNtheless, I am a NaN loather ;)
>> >
>> > Well, in a way everyone hates them too, but they *are out there*, and hitting them is nasty.
>> >
>> > This sounds an excellent solution, protecting the hapless user from
>> > the almost certainly unpleasant results of tripping over a NaN in the
>> > night ;-)
>>
>> Hi Paul, nice to meet you here again :)
>
> :-)
>
>> I am afraid though that this "solution" like every NaN-workaround for sound generic concepts is
> only a
>> bluff package that tries to heal the fundamental flaws of NaN, that are incurable by construction.
> Functor
>> NaNtheLess bends the semantic of NaN for sake of sortability:
>>
>> As the nanySet shows
>> >  {[1.#QNAN,2.22507e-308)(2.22507e-308,42]}
>>
>> we now assume that
>>
>> NaN < numeric_limits<Float>::min()
>>
>> which directly contradicts the semantics defined for NaN. If we'd extend this for infinities we
> might end up
>> with constructions like
>>
>> NaN < -numeric_limits<Float>::infinity()
>>
>> that adds just another bizarre oddity to the land of NaN sense.
>
> So it is better to be more conservative and just prohibit NaN from intervals?

In a way the NaNtheLess workaround is conservative in the sense that
it allow to deal with the user's need and at the same time keeps away
NaN from the generic library code.

I can happily live with the fact that user code, NaNtheLess in this
case, bends the NaN properties. I would not accept messing up ICL code
with NaN cases.

> Your original instinct, but maybe adding a check when creating an interval.

In user code yes, in library code NO.

> (Perhaps throw an exception if the user tries to create an interval using a NaN?)

NO, that would mean to adapt library code to NaN.

> And contains() returns false for all NaN?  (which is what Andrew wanted to start with).

This is provided by the workaround since the icl::containers and
intervals share the same ordering which is NaNtheLess when using the
workaround.

> (Of course, he could also achieve that by testing  isnan(value) ? false : contains(value)),
> and making sure that he didn't create an interval with a NaN (less risk but worse results?)

An even better solution in my view.

> Musing out loud (or should that be mumbling ;-).
:-)

The interesting thing in this thread is this: It appears to me that
everyone is fighting (or at least ignoring) NaN and its properties all
the time:

(1) icl::contains(interval<float>(1,30), NaN) == true
is considered to be a bug. But in fact this is consistent with the NaN
properties:
For all x: !(NaN < x) && !(x < NaN)

(2) We are surprised, that for Sorted Associative Containers sac we have
sac.insert(NaN).insert(x1). ... .insert(xn).size() == 1
although this is perfectly consistent with the NaN properties.

(3) In general we tend to ignore the fact that a datatype like float
is completely unusable with all std containers and algorithms relying
on Comparability concepts because NaN, that is a float value breaks
all the axioms needed for Comparability.

(4) The standard is extended by a predicate isnan that allows to
circumvent basic NaN properties like NonEqualityComparability.
Defining the NaNtheLess functor we do just that and everyone seems to
be happy with it.

Spontaneously, intuitively everyone seems to fight NaN ;-)

My own view, that is expressed in more detail in my first posting in
this thread is this:

1. We should keep NaN away from generic designs.

2. We should not mix levels of abstraction: "Special values" do not
belong to the value level of data types. Or, to put it another way,
SaNV: Special values are not values. Infinities, missing values etc.
should be handled using separate concepts.

Cheers,
Joachim

-- 
Interval Container Library [Boost.Icl]
http://www.joachim-faulhaber.de

Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk