float在内存中二进制的存储原理

 上一篇文章http://blog.csdn.net/tina224243/article/details/51919993,通过直接读取float的地址显示出二进制码。
 float的存储分为指数部分和小数部分两部分存储,本文将通过flotat的存储原理计算出二进制码,以及由二进制码反转显示float值;
 参考:http://blog.csdn.net/nethibernate/article/details/6120382

总结一下,实数转二进制float类型的方法:
A. 分别将实数的整数和小数转换为二进制
B. 左移或者右移小数点到第一个有效数字之后
C. 从小数点后第一位开始数出23位填充到尾数部分 
D. 把小数点移动的位数,左移为正,右移为负,加上偏移量127,将所得的和转换为二进制填充到指数部分
E. 根据实数的正负来填充符号位,0为正,1为负
如果需要把float的二进制转换回十进制的实数,只要将上面的步骤倒着来一边就行了。

// float转二进制,二进制转float,方法一:

#include "stdafx.h"
#include <string.h>
#include <math.h>

// 反向输出字符串;
char* back(char* in)
{
    int len = strlen(in);
    char* out = new char[len + 1];

    for (int i = len - 1; i >= 0; i--)
    {
        out[len -1 - i] = in[i];
    }
    out[len] = '\0';
    return out;
}

// 整数转二进制;
char* int2b(int ni)         
{
    int r = 0, count = 0;
    char* fint = NULL;
    char* temp = new char[32];

    do{
        r = ni % 2;
        ni = ni / 2;
        *temp++ = r + '0';
        count++;
    }while (ni > 0);
    *temp = '\0';

    printf("temp:%s\n", temp - count);
    fint = back(temp - count);
    printf("fint:%s\n", fint);

    delete [] (temp - count);
    return fint;
}

// 小数转二进制;
char* frac2b(float nf, int Lnf) 
{
    int r = 0, count = 0;
    char* ffrac = new char[Lnf + 1];

    do 
    {   
        nf = nf * 2;
        r = int(nf);
        *ffrac++ = r + '0';
        nf = nf - r;
        count++;
    }while(nf != 0 && (--Lnf) > 0);

    *ffrac = '\0';
    printf("ffrac:%s\n", ffrac - count);
    return ffrac - count;
}

// 整数部分为0时,偏移量
int expcount(char* frac2b)
{
    char* temp = frac2b;

    int count = 0; 
    while (*temp++ != '1')
    {
        ++count;
    }
    return count + 1;
}

// 整数部分为0时,小数部分右移
char* frac2b0(int ecount, char* frac2b)     
{
    char* ffrac0 = new char[24];
    int len = strlen(frac2b);
    int i = 0;

    for (i = ecount; i < len; i++)
    {
        ffrac0[i - ecount] = frac2b[i];
    }

    ffrac0[i - ecount] = '\0';

    printf("ffrac0:%s\n", ffrac0);
    return ffrac0;
}

// 指数;
char* exp2b(int Lne)
{
    char* fexp0 = new char[9];
    int offset = Lne + 127;
    char* fexp = int2b(offset);
    int lfexp = strlen(fexp); // 判断指数长度,不足8位补0;
    if (lfexp < 8)
    {
        fexp0[0] = '0';
        fexp0[1] = '\0';
        strcat(fexp0, fexp);    

        printf("fexp0:%s\n", fexp0);
        delete [] fexp; 
        return fexp0;
    }
    else
    {
        printf("fexp:%s\n", fexp);
        delete [] fexp0;
        return fexp;
    }
}

// 整数部分,二进制转十进制
int bintodec(char* pbin)
{
    char* temp = pbin;
    int len = strlen(temp);
    int binary = 0;
    for (int i = 0; i < len; i++)
    {
        int n = temp[i] - '0';
        binary += n << (len - 1 - i);
    }
    return binary;
}

// 逆运算
// 小数部分,二进制转十进制
float bintodec2(char* pbin)
{
    char* temp = pbin;
    int len = strlen(temp);
    float fbinary = 0.;
    for (int i = 0; i < len; i++)
    {
        int n = temp[i] - '0';
        fbinary += n / pow(2.0, 1.0 + i);
    }
    return fbinary;
}

// 二进制转float
void bin2float(char* bs)
{
    char* bexps = new char[9]; // 指数部分
    float n = 0.;

    // 计算偏移量
    for (int i = 0; i < 8; i++)
    {
        bexps[i] = bs[i + 1];
    }
    bexps[8] = '\0';

    int bexp =  bintodec(bexps);
    if (bexp == 0)
    {
        printf("hahaha:%s = %f\n", bs, "0.00");
    }
    else 
    {
        int offset = bexp - 127;
        if (offset < 0)
        {
            float bint0 = 0.; // 整数部分
            char* bfracs = new char[24]; // 小数部分
            int offset0 = abs(offset);//偏移量
            char* temp = new char[24];

            // 计算小数
            for (int i = 0; i < 23; i++)
            {
                bfracs[i] = bs[i + 9];
            }
            bfracs[23] = '\0';

            // 恢复去掉的0....01
            for (int i = 0; i < offset0 - 1; i++)
            {
                temp[i] = '0';
            }
            temp[offset0-1] = '1';
            temp[offset0] = '\0';

            strncat(temp, bfracs, 23 - offset0);
            float bfrac = bintodec2(temp);
            n = bint0 + bfrac;

            delete [] bfracs;
            delete [] temp;
        }
        else
        {
            char* bints = new char[offset + 2]; // 整数部分
            char* bfracs = new char[24 - offset]; // 小数部分

            // 计算整数
            bints[0] = '1';// 整数补1;
            for (int i = 1; i <= offset; i++)
            {
                bints[i] = bs[i + 8];
            }
            bints[offset + 1] = '\0';
            int bint = bintodec(bints);

            // 计算小数
            for (int i = 0; i < 23 - offset; i++)
            {
                bfracs[i] = bs[i + 9 + offset];
            }
            bfracs[23 - offset] = '\0';
            float bfrac = bintodec2(bfracs);
            n = (float)bint + bfrac;
            delete [] bints;
            delete [] bfracs;
        }

        if (bs[0] == '1')
            n = 0.0 - n;

        printf("hahaha:%s = %f\n", bs, n);

    }
    delete [] bexps;
}

void main()
{
    float orign = 0.;
    char* fint = NULL;
    char* ffrac = NULL;
    char* fexp = NULL;

    printf("Enter a  float number.\n");
    while (scanf("%f", &orign) == 1)
    {
        char* fbit = new char[33];
        float n = abs(orign);   // 先按正数计算   
        int ni = int(n);        // 整数
        float nf = n - ni;      // 小数
        fint = int2b(ni);       // 计算整数


        // 判断符号位,输入是否为0;
        if (orign == 0.)
        {
            for (int i = 0; i < 32; i++)
            {
                fbit[i] = '0';
            }
            fbit[32] = '\0';
            printf("%.3f = %s\n", orign, fbit);

            bin2float(fbit);// 逆计算
            printf("Enter a  float number.\n");
            delete [] fbit;
            delete [] fint;
            continue;
        }
        else if (orign < 0)   
            fbit[0] = '1';
        else 
            fbit[0] = '0';
        fbit[1] = '\0';

        int Lni = strlen(fint);     
        int Lnf = 24 - Lni;     // 需要计算的小数位数
        int Lne = Lni -1;       // 偏移量

        ffrac = frac2b(nf, Lnf);    // 计算小数
        char* ffrac00 = NULL;

        if (n < 1)
        {
            int ecount = expcount(ffrac);
            ffrac00 = frac2b0(ecount, ffrac);
            fexp = exp2b(-ecount);  
            // 符号位+指数位+小数位
            strcat(fbit, fexp);
            printf("singnal+fexp           :%s\n", fbit);

            strcat(fbit, ffrac00);
            printf("singnal+fexp+fint+ffrac:%s\n", fbit);
            delete [] ffrac00;
        }
        else
        {
            fexp = exp2b(Lne);          // 计算指数

            // 符号位+指数位+小数位
            strcat(fbit, fexp);
            printf("singnal+fexp           :%s\n", fbit);

            strcat(fbit, fint + 1);
            printf("singnal+fexp+fint      :%s\n", fbit);

            strcat(fbit, ffrac);
            printf("singnal+fexp+fint+ffrac:%s\n", fbit);

        }
        // 小数位,不足23位的补0;
        int len = strlen(fbit);
        if (len < 32)
        {
            for (int i = 0; i < 32-len; i++)
                fbit[len + i] = '0';
        }
        fbit[32] = '\0';

        printf("%.3f = %s\n", orign, fbit);

        bin2float(fbit);// 逆计算

        delete [] fint;
        delete [] ffrac;
        delete [] fbit;
        delete [] fexp;
        printf("Enter a  float number.\n");
    }
}

// 方法二:

// 暂不考虑负数
// 1 符号
// 8 指数 + 127
// 23 尾数 0.xxxxxxx

const static int LEN = 32;
// 整数转二进制
void int2b(int n, char* out)
{
    char* p = out;
    if (n == 0)
    {
        out[0] = '0';
        return;
    }

    while (true)
    {
        int k = n / 2;
        int j = n % 2;

        *p++ = '0' + j;
        if (k == 0)
            break;
        n = k;
    }

    // 逆向
    size_t len = strlen(out);
    char* temp = new char[len + 1];

    for (size_t i = 0; i < len; ++i)
    {
        temp[i] = out[len - i - 1];
    }
    temp[len] = '\0';

    strcpy(out, temp);
    delete[] temp;
}

// 小于1的浮点数转二进制
// 可能是无限小数
// 这里最多32位
void dec2b(double f, char* out)
{
    char* p = out;
    while (p - out < LEN)
    {
        f *= 2;
        int n = (int)f; // 整数部分
        *p++ = '0' + n;
        f -= n;

        if (f == 0)
        {
            break;
        }
    }
}

// 参数之所以用double
// 用float有效数字太少,计算含误差
char* dec2b(double d)
{
    // 得到整数部分
    char nout[LEN + 1] = { 0 };
    int n = (int)d;
    int2b(n, nout);

    // 小数部分
    double d2 = d - n;
    char dout[LEN + 1] = { 0 };
    dec2b(d2, dout);

    // 计算尾数
    size_t nlen = strlen(nout);
    char end[24] = { 0 };
    char* p = end;
    // 前半部分
    for (size_t i = 1; i < nlen; ++i)
    {
        *p++ = nout[i];
    }
    // 后半部分
    size_t dlen = strlen(dout);
    size_t rlen = 23 - (nlen - 1); // 尾数剩余空间
    if (dlen > rlen)
    {
        dlen = rlen;
    }
    for (size_t i = 0; i < dlen; ++i)
    {
        *p++ = dout[i];
    }

    // 计算指数
    char power[9] = { 0 };
    int temp = 127 + nlen - 1;
    int2b(temp, power);

    // 结果
    char* res = new char[LEN + 1];
    p = res;

    // 符号
    *p++ = '0';

    // 指数
    memcpy(p, power, 8 * sizeof(char));
    p += 8 * sizeof(char);

    // 尾数
    memcpy(p, end, 23 * sizeof(char));
    res[LEN] = '\0';

    return res;
}

int main()
{
    char* res = dec2b(6.9);
    printf(res);
    printf("\n");
    delete[] res;

    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值