您的位置:首页 > 其它

浮点数内存表示---记录一道题目

2016-01-11 12:16 337 查看
一、进制基础
1. 十进制转二进制的方法
十进制转换为二进制数时,由于整数与小数的转换方式不同,所以分别转换整数部分和小数部分再加以合并。例如将十进制整数转为二进制:把 (173)10 转换为二进制数。



例如将十进制小数转为二进制:把(0.8125)10转换为二进制小数。



十进制小数转换成二进制小数采用"乘2取整,顺序排列"法。具体做法是:用2乘十进制小数,可以得到积,将积的整数部分取出,再用2乘余下的小数部分,又 得到一个积,再将积的整数部分取出,如此进行,直到积中的整数部分为零,或者整数部分为1,此时0或1为二进制的最后一位。或者达到所要求的精度为止
二、浮点数的二进制存储方式及转换
无论是单精度还是双精度在内存中的存储中都分为三个部分:
1.符号位:用0表示正,1表示负;
2.指数位:用于存储科学计数法中的指数数据,并且采用了移位存储;
3.尾数部分:由于科学计数法中的默认第一位总是1,因此可以被舍去。例如1.01*2^2(红色的1是默认位)。
float在内存中的存储方式如下:



而双精度的内存存储方式如下:



下面记录如何将float类型转化为内存存储格式的步骤:
1.先将实数转为二进制表示。
2.将这个二进制格式实数的小数点左移或者右移n位,使得小数点移动到第一个有效数字的右边。
3.如果实数是正的则31位放入0,如果是负的31位放入1。
4.科学计数法中的指数是可以出现负数的,所以规定,指数的真实值必须再加上一个中间数,对于8位的指数,这个中间数是127;对于11位的指数,这个中间数是1023。将加后的二进制数填入22-30位。

5.最后从小数点右边第一位开始数出23位数字放入到0-22位。

三、举两个例子
例1:float型浮点数125.5转化成32位二进制浮点数

125.5的二进制码为1111101.1,写成二进制的科学计数为:1.111101*2^6(因为科学计数法“整数”部分大于1,在二进制中,“整数”部分只能恒为1) 即向左移6位,则e=6,则E=e+127=133,而E的二进制码为10000101。

所以125.5的32位二进制浮点数为

0 10000101 11110100000000000000000

例2:float型浮点数0.5转化成32位二进制浮点数

0.5的二进制码为0.1,写成二进制的科学计数为:1.0*2^(-1)即向右移1位,则e=-1,则E=e+127=126,而E的二进制码为01111110。

所以0.5的32位二进制浮点数为

0 01111110 00000000000000000000000

例3:浮点数0.0f转化为32位二进制浮点数

其实关于0.0f有两种表达形式一个是-0.0f,一个是0.0f,而他们各自的二进制表示是:

-0.0f ----> 1 00000000 00000000000000000000000

0.0f ----> 0 00000000 00000000000000000000000

下面有一段程序验证之前所说的转化的规则:

#include<stdio.h>

void main()
{
float x=-0.0f;
char *p=(char*)&x;
for (int i;=0; i<sizeof(x); ++i)
printf("%d ",*p++);
}


程序会打印出:“0 0 0 -128 ”,这里又想记录另一个概念叫大端模式和小端模式。

小端模式指的是数据的高字节保存在内存的高地址中,而数据的低字节保存在内存的低字节中。一般的Intel采用的是小端模式(据说)。数据的二进制表示从左往右就是从高到低字节。而我们知道指针是不断自增来访问下一个地址,所以高地址是后访问到。所以p所获取的二进制数分别是:

地址 --- 二进制数据

0x01---00000000

0x02---00000000

0x03---00000000

0x04---10000000

并且(10000000)2=(-128)10

最后是这个题目引发的这些的思考。

#include <iostream>
#include <stdio.h>
#include <string.h>
#include <conio.h>

using namespace std;
int main(){
float a = 1.0f;
cout << (int)a << endl;
cout << &a << endl;
cout << (int&)a << endl;
}


输出如下:

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: