博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
c语言浮点数(float double)内存存储方式------移位存储
阅读量:2433 次
发布时间:2019-05-10

本文共 2568 字,大约阅读时间需要 8 分钟。

文章目录

一、概述

C语言中,对于浮点类型的数据采用单精度类型(float)和双精度类型(double)来存储,float数据占用32bit,double数据占用64bit, float遵从的是IEEE R32.24,而double 遵从的是R64.53。

Float类型变量占4个字节,也就是32bit。单精度浮点值格式:1位符号位,8位指数,23位小数。
float变量的内存模型
具体如下:
二进制浮点数可以表示成:Float=(-1)s x M x2e
1、 符号位(sign):0代表正,1代表负。
2、 指数位(exponent):用于存储科学计数法中的指数数据,并且采用移位存储。
指数E分成三种情况:
(a)E不全为0或不全为1。指数E的计算值减去127,得到真实值,再将有效数字M前加上第一位的1。
(b)E全为0。浮点数的指数E等于1-127(或者1-1023),有效数字M不再加上第一位的1,而是还原为0.xxxxxx的小数。这样做是为了表示±0,以及接近于0的很小的数字。
(c)E全为1。这时,如果有效数字M全为0,表示±无穷大(正负取决于符号位s);如果有效数字M不全为0,表示这个数不是一个数。
3、 尾数部分(mantissa):位数部分

二进制科学计数法第一位都是1,可以将小数点前面的1省略,所以23bit的位数部分可以表示精度为24bit。

double类型占八个字节。双精度是1位符号,11位指数,52位小数。内存示例如下:
在这里插入图片描述

二、转换示例

下面讨论一下十进制数与二进制数的转换方法:

十进制:0.15625转换为二进制表示的过程如下:整数位:0小数:0.15625将小数转换位二进制的方法就是乘二,取整数部分依次从左往右放在小数点后,直至小数点后为0。0.15625x2=0.31250  取00.3125x2=0.6250 取00.625x2=1.250 取10.25x2=0.5 取00.5x2=1 取0(0.00101)2=1.01*2^(-3)符号位:0,表示位正数指数位:-3+127=124 表示为二进制数就是01111100尾数部分:1.01-1=0.01,后面不够23位的补0也就是补21个零即0.15625表示为内存中二进制数的形式为:0  01111100  010000000000000000000000  01111100  01000000000000000000000表示的数转换为十进制表示过程为:符号位:0,表示位正指数位:01111100表示的十进制为:64+32+16+8+4=124再减127=-3尾数部分:0.01 加1表示:1+0*2^(-1)+1*2^(-2)=1.25原数为:2^(-3)*1.25=0.15625

三、基于转换误差的思考

最近偶然看到一段程序,,发现了int与float转换时存在的问题,于是查询了相关的数据:

#include
int main(){ int a=9; float *p; p=&a; printf("a数值为:%d\n",a); printf("float形式为:%f\n",*p); *p=9.0; printf("a数值为:%d\n",a); printf("float形式为:%f\n",*p); return 0;}

结果令我很是不解:

a数值为:9float形式为:0.000000a数值为:1091567616float形式为:9.000000

为什么0x00000009还原成浮点数就成了0.000000?

首先,将0x00000009拆分,因为是正数所以得到第一位符号位s=0,后面8位的指数E=00000000,最后23位的有效数字M=000 0000 0000 0000 0000 1001。
由于指数E全为0,所以符合第二种情况。因此,浮点数就写成:
  (-1)0×0.00000000000000000001001×2(-126)=1.001×2(-146)
显然是一个很小的接近于0的正数,所以用十进制小数表示就是0.000000。
浮点数9.0,怎么用二进制表示?怎么还原成十进制呢?
首先,浮点数9.0等于二进制的1001.0,即1.001×2^3。
那么,第一位的符号位s=0,有效数字M等于001后面再加20个0,凑满23位,指数E等于3+127=130,即10000010。
所以,写成二进制形式,应该是S+E+M,即0 10000010 001 0000 0000 0000 0000 0000。这个32位的二进制数,还原成十进制,是1091567616。

四、为什么float有些时候表达的int数据不准确

因为int与float同样占4个字节,float表示的范围又比int大并且还包含很多小数,那int的每个值都能被float表示就是不可能的事情了。

尾数决定了浮点数的精度,尾数只有23位,加上省略的那位就是24位。如果一个int类型的值小于224,那么float是完全可以表示的。如果int类型大于224就不一定能表示了。假如一个int数值的二进制表示形式是1000000000000000000000001,表示成指数形式是1.000000000000000000000001*224,对应的float的类型尾数位是000000000000000000000001一共24位,这样就完全超出了float最多容纳23位尾数的能力。所以就不能正确表达这个int值了。由此也可以得出不能被float准确表达的最小int值是224+1。我们再将1000000000000000000000001的值加1,变成了1000000000000000000000010,这样变换为指数形式可以看出尾数又变为了23位。
也就是说25位的二进制整数最后一位是0才能被float准确表示,每2个数就有一个不能被准确表示。如果是26位的二进制整数最后两位都是0才可以被float准确表达,每4个数就有3个不能被准确表示,
即,如果是n(n>23且n为整数)位二进制数,最后n-23-1位全为0是才可以被准确表示,每2(n-23-1)个数就有2(n-23)-1位不能被准确描述。

参考教程:

转载地址:http://rptmb.baihongyu.com/

你可能感兴趣的文章
深入理解什么是Java双亲委派模型
查看>>
MySQL优化Limit查询语句
查看>>
轻松入门MySQL主从复制原理
查看>>
SpringCloud全家桶---Zuul网关
查看>>
基于zuul和ribbon的灰度发布方案
查看>>
JVM常用垃圾收集器参数说明
查看>>
MySQL索引基础知识梳理
查看>>
MySQL事务ACID底层实现原理
查看>>
关于MySQL wait_timeout问题记录
查看>>
基础算法面试题---如何用栈实现队列
查看>>
基础算法面试题---如何用队列实现栈(1)
查看>>
基础算法面试题---如何用队列实现栈(2)
查看>>
基础算法面试题---如何数组实现栈和队列
查看>>
API接口安全性设计以及各参数的作用
查看>>
《Netty权威指南 第2版》学习笔记(1)---服务端与客户端开发入门
查看>>
《Netty权威指南 第2版》学习笔记(6)--- HTTP协议开发应用
查看>>
链表算法面试题---删除链表中的重复元素II
查看>>
链表算法面试题---合并两个链表
查看>>
链表算法面试题---旋转链表
查看>>
链表算法面试题---交换链表的节点I
查看>>