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

一、进制基础

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;
}

 输出如下:

原文地址:https://www.cnblogs.com/Key-Ky/p/4427383.html