当前位置:  开发笔记 > 编程语言 > 正文

用C序列化double和float

如何解决《用C序列化double和float》经验,为你挑选了4个好方法。

如何在C中序列化双打和浮点数?

我有以下代码来序列化short,int和chars.

unsigned char * serialize_char(unsigned char *buffer, char value)
{
    buffer[0] = value;
    return buffer + 1;
}

unsigned char * serialize_int(unsigned char *buffer, int value)
{
    buffer[0] = value >> 24;
    buffer[1] = value >> 16;
    buffer[2] = value >> 8;
    buffer[3] = value;
    return buffer + 4;
}

unsigned char * serialize_short(unsigned char *buffer, short value)
{
    buffer[0] = value >> 8;
    buffer[1] = value;
    return buffer + 2;
}

编辑:

我从这个问题中找到了这些功能

编辑2:

序列化的目的是将数据发送到UDP套接字,并保证即使字节序不同,也可以在其他机器上反序列化.是否有任何其他"最佳实践"来执行此功能,因为我必须序列化整数,双精度数,浮点数和字符*?



1> R....:

可移植方式:用于frexp序列化(转换为整数尾数和指数)和ldexp反序列化.

简单的方法:假设在2010年你关心的任何机器使用IEEE float,声明一个带float元素和uint32_t元素的联合,并使用整数序列化代码来序列化float.

二进制文件 - 仇恨方式:将所有内容序列化为文本,包括浮点数.使用"%a"printf格式说明符获得一个十六进制浮点数,它总是精确表示(假设您没有限制类似的精度"%.4a")并且不受舍入误差的影响.您可以使用strtod或任何scanf一系列功能阅读这些功能.



2> S.C. Madsen..:

我记得第一次看到我的示例中使用的演员在"rsqrt"例程的古老的Quake源代码中,包含我当时看到的最酷的评论(谷歌它,你会喜欢它)

unsigned char * serialize_float(unsigned char *buffer, float value) 
{ 
    unsigned int ivalue = *((unsigned int*)&value); // warning assumes 32-bit "unsigned int"
    buffer[0] = ivalue >> 24;  
    buffer[1] = ivalue >> 16;  
    buffer[2] = ivalue >> 8;  
    buffer[3] = ivalue;  
    return buffer + 4; 
} 

我希望我能正确理解你的问题(和示例代码).如果这是有用的,请告诉我?


对于那些寻找评论的人,请参阅[this](http://en.wikipedia.org/wiki/Fast_inverse_square_root#Overview_of_the_code)维基百科链接
我会添加`char assume_sz_float_eq_sz_int [(2*(int)(sizeof(int)== sizeof(float))) - 1];`在函数的顶部.
*“但从未遇到过编译器” *基于别名的优化有一个坏习惯,即大多数时候*生成看似有效的代码。问题是没有保证。*“批评之后还没有一个(在我看来)更好的解决方案。” *在标准中已经很好地定义了通过联合或用`memcpy`复制的类型。

3> caf..:

这包一个浮点值转换成intlong long对,然后你就可以与其他功能连载.该unpack()函数用于反序列化.

这对数字分别代表数字的指数和小数部分.

#define FRAC_MAX 9223372036854775807LL /* 2**63 - 1 */

struct dbl_packed
{
    int exp;
    long long frac;
};

void pack(double x, struct dbl_packed *r)
{
    double xf = fabs(frexp(x, &r->exp)) - 0.5;

    if (xf < 0.0)
    {
        r->frac = 0;
        return;
    }

    r->frac = 1 + (long long)(xf * 2.0 * (FRAC_MAX - 1));

    if (x < 0.0)
        r->frac = -r->frac;
}

double unpack(const struct dbl_packed *p)
{
    double xf, x;

    if (p->frac == 0)
        return 0.0;

    xf = ((double)(llabs(p->frac) - 1) / (FRAC_MAX - 1)) / 2.0;

    x = ldexp(xf + 0.5, p->exp);

    if (p->frac < 0)
        x = -x;

    return x;
}



4> Michael Fouk..:

无论本机表示如何,您都可以在IEEE-754中进行便携式序列化:

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);
}

在使用IEEE-754的机器(即常见情况)中,您需要做的就是获取数字fread().否则,自己解码字节(sign * 2^(exponent-127) * 1.mantissa).

注意:在本机double比IEEE double更精确的系统中进行序列化时,您可能会遇到低位的逐个错误.

希望这可以帮助.


在适当的时候.
推荐阅读
地之南_816
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有