Boost logo

Boost :

From: Darryl Green (darryl.green_at_[hidden])
Date: 2006-02-13 20:13:38


Peter Dimov <pdimov <at> mmltd.net> writes:
> There are ways to convert FP to portable
> external representation but I haven't used them; the hack of assuming IEEE
> and same endianness as an int32/int64 works for me so far.

I think the code below is portable - but not terribly efficient. I haven't
included the actual serialization of the unpacked_real. This is something I'm
using for ASN.1 CER (I haven't tried to support all the encodings allowed by
BER!) and not with boost.serialization.

The support for infinity seems to be working for me, not sure if it is strictly
correct. I haven't tried to support any other special values, ASN.1 doesn't
support them and I don't need them.

Presumably ASN.1 BER would make a reasonable portable binary archive format
(basically a binary equivalent of XML) and includes variable length sequence
size encoding in the format. Is there any interest in this? I would expect ASN.1
BER to be slower to encode/decode than a more "raw" binary format and I'm not
sure that it really makes much sense when used in an environment where the
syntax is really defined by the data, not by an ASN.1 or other specification.

struct unpacked_real
{
    bool negative_, inf_;
    unsigned long mantissa;
    int exp;

    enum {
        scale = sizeof(unsigned long)*8-1
    };

    bool is_zero()
    {
        return (mantissa == 0 && exp == 0);
    }

    bool is_inf()
    {
        return inf_;
    }
    
    unpacked_real() :
        negative_(false),
        inf_(false),
        mantissa(0),
        exp(0)
    {}
    
    template <class Real>
    unpacked_real(const Real &x)
    {
        Real m;
        negative_ = x < 0.0;
        if (inf_ = test_inf(x)) return;
        if (x == 0.0)
        {
            mantissa = 0;
            exp = 0;
            return;
        }
        
        if (negative_)
            m = frexp(-x, &exp);
        else
            m = frexp(x, &exp);
        
        mantissa = (unsigned long )ldexp(m, scale);
        exp -= scale;
        while (!(mantissa & 1)) {
            mantissa >>= 1;
            exp += 1;
        }
    }

    operator float()
    {
        if (inf_ && negative_) return -std::numeric_limits<float>::infinity();
        if (inf_ && !negative_) return std::numeric_limits<float>::infinity();
        
        float v = mantissa;
        v = ldexp(v,exp);
        if (negative_) v = -v;
        return v;
    }

    operator double()
    {
        if (inf_ && negative_) return -std::numeric_limits<double>::infinity();
        if (inf_ && !negative_) return std::numeric_limits<double>::infinity();
        
        double v = mantissa;
        v = ldexp(v,exp);
        if (negative_) v = -v;
        return v;
    }

    private:
        template <class T>
            bool test_inf(const T&x)
            {
                return ( x > std::numeric_limits<T>::max() || x <
-std::numeric_limits<T>::max() );
            }
};


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