C浮点数据格式

#include <stdio.h>

int main(int argc, char *argv[])
{
    float p = 5.1f;
    int f = (int)(p*100);
    printf("%d", f);
    getch( );
    return 0;
}

我想要输出 510,可是机器nnd居然输出509(竟然敢扣我工钱)。
到底是what's wrong。我上看下看,左看又看,看了又看,就是发现不了错误。
于是我试着把5.1改成5.5,一切正常啊。捣鼓了N个小时后猜想,莫非是浮点数的表示问题,
于是花了很久找到浮点数的机器表示方法,照着规定克隆操作了一下。(据说练过乾坤大
挪移的人什么招式都可以克隆)。

IEEE规定的浮点数的机器表示:

32位机器的 float 是4字节的,共32位。
第1位是符号位,接着8位指数位,接着23位基数位。
以5.1为例。

5 = 101 (2进制)

0.1 = 0.0 0011 0011 0011 0011 0011 0011 .....(无限循环)

所以 5.1 = 101.0 0011 0011 0011 0011 0011 0011 0011 0011 ...

5.1= 1.010 0011 0011 0011 0011 0011 0011 0011 0011 0011... * 2^2

因为第一位总是为1,如果是0,就移动小数点直到是非0的,所以第一位的1丢弃。
得到 010 0011 0011 0011 0011 0011 0011 0011 0011....
取23位 得到 0100 0110 0110 0110 0110 011

接着看指数部分
指数是2, 根据规定,指数统一+127再转换为无符号8位2进制数,
2+127=129 (1000 0001)

存储的时候指数部分存储在基数之前,这样就有31位了,
因为5.1是正的,所以符号为是0,存储在指数部分之前

这样就得到 0100 0000 1010 0011 0011 0011 0011 0011

我们来看一下机器上是否真的如此

#include <stdio.h>
#include <stdlib.h>

int main(int argc, char *argv[])
{
    float a=5.1;
    int *i=&a;
    printf("%x", *i);
    system("PAUSE");
    return 0;
}

40a33333
0100 0000 1010 0011 0011 0011 0011 0011

果真是一样的。

这个例子就说明了为什么浮点数有时存在这样的问题。
这个数化为10进制整数的时候,
由于不可能达到5.1(5.099..)
所以×100后截取了前面的值 509。 

32位机器上float 的表示
对于大小为32-bit的浮点数(32-bit为单精度,64-bit浮点数为双精度,80-bit为扩展精度浮点数),
1、其第31 bit为符号位,为0则表示正数,反之为复数,其读数值用s表示;
2、第30~23 bit为幂数,其读数值用e表示;
3、第22~0 bit共23 bit作为系数,视为二进制纯小数,假定该小数的十进制值为x;

则按照规定,该浮点数的值用十进制表示为:
= (-1)^s * (1 + x) * 2^(e - 127)

对于49E48E68来说,
1、其第31 bit为0,即s = 0
2、第30~23 bit依次为100 1001 1,读成十进制就是147,即e = 147。
3、第22~0 bit依次为110 0100 1000 1110 0110 1000,也就是二进制的纯小数0.110 0100 1000 1110 0110 1000,其十进制形式为0.78559589385986328125,即x = 0.78559589385986328125。

原文地址:https://www.cnblogs.com/sunkang/p/2038838.html