Serialize double and float with C

后端 未结 8 1269
孤街浪徒
孤街浪徒 2020-12-01 09:47

How can I serialize doubles and floats in C?

I have the following code for serializing shorts, ints, and chars.

unsigned char * serialize_char(unsign         


        
8条回答
  •  一个人的身影
    2020-12-01 10:22

    You can portably serialize in IEEE-754 regardless of the native representation:

    int fwriteieee754(double x, FILE * fp, int bigendian)
    {
        int                     shift;
        unsigned long           sign, exp, hibits, hilong, lowlong;
        double                  fnorm, significand;
        int                     expbits = 11;
        int                     significandbits = 52;
    
        /* zero (can't handle signed zero) */
        if(x == 0) {
            hilong = 0;
            lowlong = 0;
            goto writedata;
        }
        /* infinity */
        if(x > DBL_MAX) {
            hilong = 1024 + ((1 << (expbits - 1)) - 1);
            hilong <<= (31 - expbits);
            lowlong = 0;
            goto writedata;
        }
        /* -infinity */
        if(x < -DBL_MAX) {
            hilong = 1024 + ((1 << (expbits - 1)) - 1);
            hilong <<= (31 - expbits);
            hilong |= (1 << 31);
            lowlong = 0;
            goto writedata;
        }
        /* NaN - dodgy because many compilers optimise out this test
         * isnan() is C99, POSIX.1 only, use it if you will.
         */
        if(x != x) {
            hilong = 1024 + ((1 << (expbits - 1)) - 1);
            hilong <<= (31 - expbits);
            lowlong = 1234;
            goto writedata;
        }
    
        /* get the sign */
        if(x < 0) {
            sign = 1;
            fnorm = -x;
        } else {
            sign = 0;
            fnorm = x;
        }
    
        /* get the normalized form of f and track the exponent */
        shift = 0;
        while(fnorm >= 2.0) {
            fnorm /= 2.0;
            shift++;
        }
        while(fnorm < 1.0) {
            fnorm *= 2.0;
            shift--;
        }
    
        /* check for denormalized numbers */
        if(shift < -1022) {
            while(shift < -1022) {
                fnorm /= 2.0;
                shift++;
            }
            shift = -1023;
        } else {
            /* take the significant bit off mantissa */
            fnorm = fnorm - 1.0;
        }
        /* calculate the integer form of the significand */
        /* hold it in a  double for now */
    
        significand = fnorm * ((1LL << significandbits) + 0.5f);
    
        /* get the biased exponent */
        exp = shift + ((1 << (expbits - 1)) - 1);   /* shift + bias */
    
        /* put the data into two longs */
        hibits = (long)(significand / 4294967296);  /* 0x100000000 */
        hilong = (sign << 31) | (exp << (31 - expbits)) | hibits;
        lowlong = (unsigned long)(significand - hibits * 4294967296);
    
     writedata:
        /* write the bytes out to the stream */
        if(bigendian) {
            fputc((hilong >> 24) & 0xFF, fp);
            fputc((hilong >> 16) & 0xFF, fp);
            fputc((hilong >> 8) & 0xFF, fp);
            fputc(hilong & 0xFF, fp);
    
            fputc((lowlong >> 24) & 0xFF, fp);
            fputc((lowlong >> 16) & 0xFF, fp);
            fputc((lowlong >> 8) & 0xFF, fp);
            fputc(lowlong & 0xFF, fp);
        } else {
            fputc(lowlong & 0xFF, fp);
            fputc((lowlong >> 8) & 0xFF, fp);
            fputc((lowlong >> 16) & 0xFF, fp);
            fputc((lowlong >> 24) & 0xFF, fp);
    
            fputc(hilong & 0xFF, fp);
            fputc((hilong >> 8) & 0xFF, fp);
            fputc((hilong >> 16) & 0xFF, fp);
            fputc((hilong >> 24) & 0xFF, fp);
        }
        return ferror(fp);
    }
    

    In machines using IEEE-754 (ie. the common case), all you'll need to do to get the number is an fread(). Otherwise, decode the bytes yourself (sign * 2^(exponent-127) * 1.mantissa).

    Note: when serializing in systems where the native double is more precise than the IEEE double, you might encounter off-by-one errors in the low bit.

    Hope this helps.

提交回复
热议问题