蛋疼的浮点数

浮点型和实型:实型是数学的说法,只采用十进制,而浮点型则是计算机的表示小数的方法,名称意味着小数点的位置是浮动的.

标准C允许浮点数使用后缀(F or f),比如356f和356.是等价的.

 

先来明确几个概念:

位模式:计算机中二进制的0、1代码所组成的数字串.
浮点标准:蛋疼的浮点数 ,在浮点数中,底数一直为2.

蛋疼的浮点数,其中e是无符号的8或16位数.

尾数(域):也叫有效数,是一个二进制小数,它的范围是[0,1)或[1,2),因为规定规格化值中小数点的左侧必须为1,既然第一位总是1,我们就不需要显式地来表示它了.

(1)当浮点数尾数M=0,无论阶码E为何值,则该浮点数为0值;

(2)当阶码的值遇到比它所能表示的最小值还小时,不管尾数M为何值,则浮点数为0值.

(1)、(2)中的零值称为机器零

移码:一个n位的数中,因为有正数和负数,一定要是2^n或2^n-1才行,才会有移码的特征(负数变成最小的数,才能让我们光从数值上就可以判断其大小),换言之,移码就是127(单精度)或1023(双精度),这样可以让我们直观的看出阶码的大小.

 

那么为什么移码值是127而不是128呢?假设是128,且此时指数E=127,则e=E+Bias=127+128=255,此时指数全为1,这是无穷大的情况;如果此时指数是0(包括+0和-0),那么e=+0+128,或e=-0(补码)+128=0(溢出),所以当指数E=0时,存在非规格化数.

由于8位E中,只有7位有效数字,7位能表示的大小为0-127,所以偏移量可以在0-127中任取一值,在IEEE754中规定取127.

 

标准4字节浮点型(单精度型)在计算机里的存储方式如下图(以下所有的位都是二进制位,即01二进制串):

蛋疼的浮点数

浮点数的具体格式如下:

  

符号域

指数域

小数域

指数偏移量

单精度浮点数

1 位[31]

8位[30-23]

23位[22-00]

127

双精度浮点数

1 位[63]

11 位[62-52]

52 位[51-00]

1023

 

一.规格化值:

小数点的左侧必须为1,这样就可以腾出一个二进制位来保存更多的尾数.

当exp不全为0(数值0)或全为1(单精度数值是255,双精度是2047)时.

在这种情况下,指数域解释为表示偏置形式的有符号整数,

蛋疼的浮点数

举例:

1.已知一个单精度浮点数用16进制数表示为:0xC0B40000,求此浮点数所表达的实数.

先转换为二进制形式(注意:对于负数二进制补码转换成十进制一定要:先取反,后加1)

C0B40000

1100 0000 1011 0100 0000 0000 0000 0000(32位)

按照浮点数格式切割成相应的域 1 1000 0001 01101 000000000000000000

蛋疼的浮点数

经分析:符号域1 意味着负数;指数域为129 意味着实际的指数为2 (减去偏差值Bias 127);尾数域为01101意味着实际的二进制尾数为1.01101 (加上隐含的小数点前面的1).所以,实际的实数为:

= -1.01101 × 2^ 2=- ( 1*2^0 + 1*2^(-2) + 1*2^(-3) + 1*2^(-5) ) ×2^2

= -(1+0.25+0.125+0.03125)*4

= -1.40625*4 = -5.625.

 

2. 将实数-9.625变换为相应的浮点数格式.

1) 求出该实数对应的二进制:1001.101,用科学技术法表达为:-1.001101 ×2^3;

2) 因为负数,符号为1;

3) 指数为3,故指数域的值为3 + 127 = 130,即二进制的10000010;

4) 尾数为1.001101,省略小数点左边的1后为001101,右侧0补齐,补够23位,

最终尾数域为:00110100000000000000000;

5) 最终结果:1 1000001000110100000000000000000,用16进制表示:0xC11A0000.

 

验证代码如下(关于强制指针转换的知识点见上篇):

#include<stdio.h>   
#include<stdlib.h>
  
 int main()  
 {  
    float f =-9.625;  
    printf("0x%x", *(int*)&f);//打印0xC11A0000 (机器级的表示)
    return 0;  
}  


注:代码来自:http://blog.csdn.net/justheretobe/article/details/7703575

 

二.非规格化值:指数域全为0时所表示的数,即

为什么要使用非规格化值呢?一是为了表示数值0而设的,因为规格化数的M>=1(在规格化数值表示法中的M是隐含以1为开头的表示),因此我们无法表示0.实际上,+0.0的浮点表示的位模式为全0:符号位是0,指数域全为0(表示是一个非规格化值),而小数域也全为0.二是为了用来表示那些非常接近域0.0的数.它们提供了一种属性,称为逐渐溢出,其中,可能的数值分布均匀的接近于0.0.

验证代码如下:

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

typedef struct _float
{ 
    intw:2;     //表示i只有一个bit位有效.如果后面紧跟有:int b:1;则a和b会共用一个int
    intj:8;     //另外结构体在内存中是从低位开始存储的,理解内存这一点对本程序至关重要
    ints:1; 
}Float; 
int main() 
{ 
    float f =0; 
    Floatobj; 
    obj.s =0;        //若等于1呢?结果为-0.000000
    obj.j =0; 
    obj.w=0x400000;   //表结构体所占内存的值为000000000 01000000000000000000000
    f =*(float*)(&obj); 
    printf("%f",f);   //输出0.000000 (f=+0.01*2^(1-127))——无限接近0
    return0; 
}


 

三.无穷大

符号位:1bits

阶码:8bits

尾数:23bits

x

1111 1111

0000 0000 0000 0000 0000 000

代码示例:

#include<stdio.h>

#include<stdlib.h>

typedef struct _float
 { 
      int  w:23; 
      int  j:8; 
      int  s:1; 
}Float; 
int main() 
      float f = 0; 
      Float obj; 
      obj.s = 0; 
      obj.j = 0xff; 
      obj.w = 0x0; 
       f = *(float*)(&obj); 
       printf("%f", f); //输出inf 
       return 0; 
}

 
  

 4.NON

符号位:1bit

阶码:8bits

尾数:23bits

x

1111 1111

非全0

代码示例:

<p align="left"><span style="background-color: rgb(240, 240, 240);">#include<stdio.h></span></p><p align="left"><span style="background-color: rgb(240, 240, 240);">#include<stdlib.h></span></p>typedef struct _float  
{  
    int w:23;  
    int j:8;  
    int s:1;  
}Float;  
int main()  
{  
    float f = 0;  
    Float obj;  
    obj.s = 0;  
    obj.j = 0xff;  
    obj.w = 0x1;  
    f = *(float*)(&obj);  
    printf("%f", f);   //输出nan  
    return 0;  
}  

注1:

 double a=pow(2,-126);
 printf("%f\n",a);             //a=0.000000(实型输出)

注2:

浮点寄存器一般采用一种特殊的80位的扩展精度格式,以使得精度更高,范围更广。所有的单精度和双精度数在从存储器加载到浮点寄存器中时,都会转换成这种格式,运算总是以扩展精度格式来进行的,当数字存储在存储器中时,它们就从扩展精度转换成单精度或者双精度格式。这样的特性有时候会产生奇怪的结果(深入理解寄存器和存储器的区别——调用函数的栈就是在存储器中,而寄存器当前只能存储需要的少量值)

注3:

浮点型数据不能直接表示大小,这是没有意义的,但是可以用诸如fabs(a-b)<1e-5(1*10^(-5))的方法来进行条件判断。

总结:大多数机器对整数使用二进制补码编码,而对浮点数使用IEEE编码。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值