Boost logo

Boost :

From: Paul A Bristow (pbristow_at_[hidden])
Date: 2005-11-20 10:07:23


 

| -----Original Message-----
| From: boost-bounces_at_[hidden]
| [mailto:boost-bounces_at_[hidden]] On Behalf Of troy d. straszheim
| Sent: 18 November 2005 15:19
| To: boost_at_[hidden]
| Subject: Re: [boost] serialization - NaN, +/Inf and others
|
| On Thu, Nov 17, 2005 at 10:00:01AM -0800, Robert Ramey wrote:
| > The 32-bit IEEE 754 representations of these values are:

For the record, I found this by far the most useful site:

http://babbage.cs.qc.edu/IEEE-754/IEEE-754references.html

| I don't think archives should attempt to guarantee that
| floating point types that are denormalized or inf or nan, in any form,
| are to-the-bit identical after a trip through one of the the
| serialization library's text archives (and it should guarantee only
| that zero is still zero). It's a text archive, you get a text
| representation, and there is no standard for text representations of
| wacky floating-point types. Fullstop.

Agree.

|
| Looks like John Maddock figured the general isinf()/isnan() problem
| out in a general way:
|
| #include <math.h> // isnan where available
| #include <cmath>
|
| namespace boost{ namespace math{ namespace detail{
|
| template <class T>
| inline bool test_is_nan(T t)
| {
| // Comparisons with Nan's always fail:
| return !(t <= std::numeric_limits<T>::infinity())
| || !(t >= -std::numeric_limits<T>::infinity());
| }
| #ifdef isnan
| template<> inline bool test_is_nan<float>(float t) { return
| isnan(t); }
| template<> inline bool test_is_nan<double>(double t) {
| return isnan(t); }
| template<> inline bool test_is_nan<long double>(long double
| t) { return isnan(t); }
| #endif

In principle, yes, but

isnan() and isinf() ideally should be provided by C99/TR1.

TR1 8.16.1 Synopsis

// C99 macros defined as C++ templates.
template<class T> bool signbit(T x);
template<class T> int fpclassify(T x);
template<class T> bool isfinite(T x);
template<class T> bool isinf(T x);
template<class T> bool isnan(T x);
 
(For Microsoft, and I believe several other environments, they could be a
_isnan() etc lightly wrapped for C++?), something like:

#include <cfloat> // for MSVC <float.h> for _isnan, _finite, _fpclass &
values.

/* IEEE recommended functions */

#ifndef _SIGN_DEFINED
_CRTIMP __checkReturn double __cdecl _copysign (__in double _Number, __in
double _Sign);
_CRTIMP __checkReturn double __cdecl _chgsign (__in double _X);
#define _SIGN_DEFINED
#endif
_CRTIMP __checkReturn double __cdecl _scalb(__in double _X, __in long _Y);
_CRTIMP __checkReturn double __cdecl _logb(__in double _X);
_CRTIMP __checkReturn double __cdecl _nextafter(__in double _X, __in double
_Y);
_CRTIMP __checkReturn int __cdecl _finite(__in double _X);
_CRTIMP __checkReturn int __cdecl _isnan(__in double _X);
_CRTIMP __checkReturn int __cdecl _fpclass(__in double _X);

#define _FPCLASS_SNAN 0x0001 /* signaling NaN */
#define _FPCLASS_QNAN 0x0002 /* quiet NaN */
#define _FPCLASS_NINF 0x0004 /* negative infinity */
#define _FPCLASS_NN 0x0008 /* negative normal */
#define _FPCLASS_ND 0x0010 /* negative denormal */
#define _FPCLASS_NZ 0x0020 /* -0 */
#define _FPCLASS_PZ 0x0040 /* +0 */
#define _FPCLASS_PD 0x0080 /* positive denormal */
#define _FPCLASS_PN 0x0100 /* positive normal */
#define _FPCLASS_PINF 0x0200 /* positive infinity */

namespace std
{
        namespace tr1
        {
                bool isnan(double x)
                {
#ifdef BOOST_MSVC || ...
                        return _isnan(x);
#elif
...
#else
#error "isnan not available for this environment!"
#endif
                }
                bool isinf(double x)
#ifdef BOOST_MSVC || ...
                        return _finite(x);
                }
                bool signbit(double x)
#ifdef BOOST_MSVC || ...
                        return _copysign(x); // or used result from fpclass.
                        if -inf || -normal || - -zero then negative ...
                }
        } // namespace tr1
} // namespace std

Or this could be done using the result from _fpclass(fpclassify in TR1),
also widely available? (Feedback on any for which it is NOT available?

Sadly John Maddock hasn't yet completed even these few IEEE recommended from
the C99 additions?
Has anyone else? Surely we should try to get these into Boost asap?

| So I'd suggest the following: for some D of type T, the following
| expressions will evaluate the same both before and after a round-trip
| through a text archive:
|
| test_is_nan(D) // (also isnan(D) if available)
|
| D <= -std::numeric_limits<T>::infinity() // also (isinf(D) && (D < 0)),
etc
|
| D >= std::numeric_limits<T>::infinity()
|
| No more is guaranteed. This addresses the real-world use cases
| without getting too intimiate with ieee754.
|
| So one could use that kind of thing to detect them, then just set them
| to nan/inf/-inf given by
|
| std::numeric_limits<T>::infinity()
| -std::numeric_limits<T>::infinity()
| std::numeric_limits<T>::quiet_NAN()

So ALL the many possible NaN values will be represented as quiet_NAN().
(This would be useful if NaN is used to represent 'missing' values).

Yes, although one could use fpclassify(), another TR1 function, or signbit()
to detect negative zero (as well as negative infinity).

But the fact that that the XML schema,
http://www.w3.org/TR/xmlschema-2/#float , ignores negative zero suggests
that it is not worth doing here. ('Real Mathematicians' who want this
feature, or true NaN values, will have to use a binary archive, or some
other workaround).

I trust that this does not imply that EVERY floating point value has to
include in the archive a byte signalling if it is a 'funny' number, or not?
I trust I misunderstood the serialization proposed.

Paul

PS If you want to ONLY deal with IEEE formats, code below works - but a
macro would be better to make an error ***at compile time***.

Anyone know how to do this? I can't find any corresponding MACRO in C99. Do
we need one?

// Check is IEEE 754 - but really want a macro.
if (!numeric_limits<double>::is_iec559)
{ // Code below is not portable.
        cout << "is NOT IEC559!" << endl;
        return -1;
}

-- 
Paul A Bristow
Prizet Farmhouse, Kendal, Cumbria UK LA8 8AB
Phone and SMS text +44 1539 561830, Mobile and SMS text +44 7714 330204
mailto: pbristow_at_[hidden]  www.hetp.u-net.com

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