|
Boost : |
Subject: Re: [boost] New Boost.XInt Library, request preliminary review
From: Joachim Faulhaber (afojgo_at_[hidden])
Date: 2010-04-07 17:04:01
2010/3/29 Chad Nelson <chad.thecomfychair_at_[hidden]>:
> -----BEGIN PGP SIGNED MESSAGE-----
> Hash: SHA1
>
>>>> An xint::integer which is +infinity or -infinity is more meaningful than
>>>> one which is NaN.
>>>
>>> Agreed -- but only slightly. It carries one additional bit's worth of
>>> meaning, the sign.
>>
>> Even if you identify +infinity and -infinity as a single infinity, it
>> should *still* mean something different from an NaN. You might group
>> infinity into the class of NaNs, but that doesn't mean that every
>> operation which results in an NaN may as well result in an infinity
>> (signed or unsigned). 0/0 and sqrt(-1) should evaluate to an NaN (or
>> throw); it would be unsettling to evaluate these as infinity.
>
> I guess I'm not explaining myself very well. I was suggesting using the
> NaN value as infinity only where you need an infinity value. The only
> viable use I've seen suggested for infinity, in this library, is for
> unbounded intervals (which I'll address below).
>
>>>> At the very least, you can make more refined calculations and
>>>> comparisons with +/-infinity (compared to NaN),
>>>
>>> Do you have an example where this would make any noticeable difference
>>> in XInt?
>>
>> Noticeable in what sense? 1/NaN is NaN; 1/+infinity is +0 (or
>> 1/infinity is 0 if you don't want signed infinities and zeros).
>> Assuming, of course, you allow calculations with NaNs.
>
> Noticeable in the sense that it would make any difference to people
> using the library.
>
>>> An interval consists of two points. Setting the lower point to
>>> Not-a-Number would work exactly the same as setting it to -infinity.
>>> Same with the higher point and +infinity. It wouldn't make any sense to
>>> set the lower point to +infinity, or the higher one to -infinity, so the
>>> sign doesn't convey any useful information in that case.
>>
>> Since NaN compares false to anything else, good luck getting your
>> intervals with NaN endpoints to work in any kind of generic setting ;)
>
> Now that's a decent argument for infinity values. Though I'm still not
> sure whether they'd ever be used... is there a scientific or
> mathematical use of intervals that you can foresee this library being
> used for?
Hi Chad,
as an author of a library of intervals and interval containers, I have
encountered places in my library design, where infinity values not
only seemed to be useful but also appeared to be a "natural" solution.
Natural, in this context means, easy to understand and in line with
common math knowledge.
(1) Complement of an interval set:
complement({[0..0]}) == {(-inf..0), (0..+inf)}
If we had infinity values, we could always define the complements of
interval sets, like in the example above.
(2) Size of an interval set:
Throughout the stl, the size function returns the number of elements
for containers.
So for an std::set, we have
{1,2, 5,6,7}.size() == 5
As interval set of integers this is
{[1..2], [5..7]}.size() == 5
but for an interval set of doubles we have a "theoretic" result
{[1.0..2.0], [5.0..7.0]}.size() == inf
because the number of elements in this set of reals is *theoretically*
infinite.
In both cases, if felt kind of compelled to use infinity values.
While these use cases seem to provide good reasons to introduce
infinity values for integral numbers, I never had any use for "not a
number" values. Contrary to infinities that are a part both of natural
and mathematical language, not-a-number values appear pretty bizarr to
me ... Their meaning is a contradiction in itself and their properties
are non-intuitive.
Meanwhile I doubt the usefulness of both of them, NaN and Infinity, on
fundamental numeric types. Since there is the IEEE 754 for floating
point numbers that proposes them, there is probably a vast amount of
mathematical and numerical expert knowledge that this standard is
based on. But my gut feeling is different.
I think, the values of a numeric types should be
(1) closed under their fundamental operations e.g. +.
(2) Their values should be reachable from the initial value 0 or T()
applying (fundamental) operations.
Where operations are not defined like y/0, instead of introducing NaN,
the undefined case should be guarded against by
(1) program logic (asserts) or
(2) denominator checks, if the condition can not be determined from
the program logic otherwise.
Neither NaN nor +/-Inf can be computed from 0 using fundamental
operations like ++, +, -- and -. But the user can assign them to
variables
integer myNaN = integer(not_a_number());
and pass them to any operation that is provided by your type. So you
have to check for NaN in every single function you implement. IIUC you
provide NaN as emergency result for 3 functions only. Neither of these
is fundamental to integral types. I don't think these functions
justify to spoil the whole type with NaNs.
My be it would be more interesting to provide the minimal and "pure"
numeric type and provide a NaN and Infinity closure as template
template<class IntegralT, class ClosureTraits=...> closed { ... }
because the way in which NaNs, Infinities (and maybe more special
values) are handled should be the same for all the different
implementations of integral numeric types.
Concerning my own yearning for infinity, I had the insight, that I can
provide infinitely open interval borders myself as a property of my
interval type. So I can be independent of the properties of my
parameter types in case of example (1: complement). For example (2:
size) I can provide an is_infinite() function instead, with a little
loss of simplicity though.
Generally I think we should avoid special values for integral numeric types.
Thank you for submitting your library. If I find time, I might try to
use it with my ITL library of interval containers.
Cheers
Joachim
Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk