逆向——浮点数的表示,遇到了就去在线查吧,还原起来比较难受

第二节 2.5数据类型与存储
 
浮点数这玩意自己去在线转换下就行了:
 
http://www.styb.cn/cms/ieee_754.php
 

 

 
 
 
详细:
 

 

 

 

 

 

 

 

 

第二节 2.6浮点数的存法

记住知识点:

1、小数点左移,指数部分:指数减1的二进制数

 

 

2、小数点右移,指数部分:指数的二进制数,取反

 

 

3、符号位:正0,负1
4、小数点方向位:左1,右0


—————————————————————————————

例1:8.25的存法:

 

 

 

 

 ————————————

 

 

例2:0.7的存法:

 

 

 

 

 

 

 


 

整数类型

在之前的课程中我们提到了变量,变量就是一种容器,我们可以存储数据在里面,里面的数据也可以被我们修改;但是这个容器能存储多少数据,存储什么样格式的数据就取决于变量类型(数据类型)。

在C语言中变量类型有这几种:

  1. 基本类型:整数、浮点

  2. 构造类型:数组、结构体、共用体(联合)

  3. 指针类型

  4. 空类型:void

这节课我们先来学习以下整数类型:

名称

数据宽度

数据范围

char

8BIT = 1字节

0 - 0xFF

short

16BIT = 2字节

0 - 0xFFFF

int

32BIT = 4字节

0 - 0xFFFFFFFF

long

32BIT = 4字节

0 - 0xFFFFFFFF

:int在16位计算机中与short宽度一样,在32位及以上的计算机中与long相同。

如果我们存储的数据宽度比变量的数据宽度大就会出现数据溢出,如下示例代码:

char x = 0x100;

这种情况下,数据是如何存储的呢?我们还可以来看一下汇编代码:

images/download/attachments/12714021/image2021-2-17_23-13-28.png

可以看见这里在汇编中直接存储的是0(十六进制),因为这里的数据宽度是1个字节,也就是8位二进制,其二进制则为0000 0000,100我们可以转为二进制:0001 0000 0000

由此得出一个结论:当数据存储超出其数据宽度造成数据溢出时,存储数据舍弃高位,存储低位。以上例子可能不明显,可以看如下例子:

images/download/attachments/12714021/image2021-2-17_23-18-7.png

 

整数的存储格式如下:

char x = 1; // 0000 0001
char x = -1; // 1111 1111

至于为什么这样存储,还需要去回顾一下「原码、反码、补码」的相关知识。

 

在之前的汇编学习中,我们了解到有符号数和无符号数,同样在C语言中,也可以表示有符号数与无符号数,在C语言中不添加如下关键词,默认就是有符号数

signed char x = -1; // 有符号数
 
unsigned char a = -1; // 无符号数

在什么时候去使用有符号、无符号呢?

  1. 有符号:涉及负数的领域,如炒股

  2. 无符号:无负数的领域,如年龄

如上代码,我们可以看下反汇编:

images/download/attachments/12714021/image2021-2-18_0-15-53.png

这时候,可能会有人疑惑,为什么定义了变量a为无符号数,存储-1的内容还是0xFF呢?这是因为在编译器中,不管你是如何定义这个数的,只要看见-1,那么一定会以其补码形式存储

有符号数与无符号数存储数据是没有区别的,只有在扩展与比较时才会存在区别。

如下示例代码,定义一个char类型的变量,再赋值给一个int类型的变量:

char x = -1; // 0xFF 1111 1111
int y = x;

因为在C语言中不添加如下关键词,默认就是有符号数,所以这里就是两个有符号数的赋值,变量x给到y,y的值就是0xFFFFFFFF,这是为什么?int类型代表4个字节,也就是32位二进制数:0000 0000 0000 0000 0000 0000 0000 0000,在这里x为1111 1111,那么二进制数为:二进制数:0000 0000 0000 0000 0000 0000 1111 1111,但由于这是一个有符号数,所以其余位为符号位,也就是1,最终二进制数为:1111 1111 1111 1111 1111 1111 1111 1111,也就是0xFFFFFFFF

无符号数则不需要如此:

unsigned char x = -1; // 0xFF 1111 1111
int y = x;

这里最后变量y的值则为255,也就是0000 0000 0000 0000 0000 0000 1111 1111

 

在比较时候也存在区别,例如:

int a = 1; // 0x1
int b = -1; // 0xFF

这里是有符号数比较a和b,a确实是大于b的,但无符号数不一样:

unsigned int a = 1; // 0x1 1
unsigned int b = -1; // 0xFF 255

这里在比较,则b大于a。

浮点类型

浮点类型分为这几类:

名称

数据宽度

float

32BIT = 4字节

double

32BIT = 8字节

long double

32BIT = 8字节(在某些平台的编译器中可能是16个字节)

建议赋值方式:

float a = 1.23F;
double b = 2.34;
long double c = 2.34L;

我们在日常使用中最常用的就是float、double类型;会有人好奇,为什么在这里要在数据最后加上F或L?就以float举例,如果不加上F,编译器默认会认为这个值是double,然后再转换赋值给float。

 

float和double在存储的方式上都遵从IEEE编码规范:

images/download/attachments/12714021/image2021-2-18_16-12-42.png

我们主要了解一下float类型的存储格式即可,其他类型举一反三都可以进行推演。

这里我们举例说明8.25转成浮点存储,整数部分8不断的除以2,直到结果为0,整除不包含小数点,所以最后的1/2结果为0,有余数则为1。

images/download/attachments/12714021/image2021-2-18_16-16-28.png

从下往上读,由此可以得出8的二进制为1000,我们还可以来算一下9的二进制:

9/2 = 4 1

4/2 = 2 0

2/2 = 1 0

1/2 = 0 1

得出9的二进制为1001,得出结论:所有的整数一定可以完整的转换为二进制

8.25转成浮点存储,小数部分这样计算:

images/download/attachments/12714021/image2021-2-18_16-22-43.png

小数部分0.25不断的乘以2,直到结果小数点为0,例如:1.0,而如果大于1.0则二进制位也为1,其余都是0,这里我们以0.4为例子:

images/download/attachments/12714021/image2021-2-18_16-23-3.png

0.8*2=1.6,1.6的1拿走则表示二进制位为1,然后再乘以2,以此类推...但是这里我们发现这里就进入了循环状态,一直都是0110,永远无法得到结果小数点为0的情况。

由此得出结论:用二进制描述小数,不可能做到完全精确,就像用十进制描述1/3一样

将一个float型转化为内存存储格式的步骤:

 

  • 先将这个实数的绝对值化为二进制格式

  • 将这个二进制格式的实数的小数点左移或者右移N位,直到小数点移动到第一个有效数字的右边

  • 从小数点右边第一位开始数出二十三位数字放入第22到第0位

  • 如果实数是正的,则第31位放入“0”,否则放入 “1”

  • 如果n是左移得到的,说明指数是正的,第30位放入“1”,如果n是右移得到的或n=0,则第30位放入“0”

  • 如果n是左移得到的,则n减去1后化为二进制,并在左边加“0”补足七位,放入第29到第23位

  • 如果n是右移得到的或n=0,则将n化为二进制后在左边加“0”补足七位,再各位求反,再放入第29到第23位

 

8.25 -> 100.01 -> 1.00001 * 2的三次方(指数是3)

科学计数法

10 = 1 * 10一次方 指数:1
100 = 1 * 10的二次方 指数:2
1000 = 1 * 10的三次方 指数:3

填充表格(flot)

符号位(1) 指数部分(8) 尾数部分(23)

0 10000010 000 0100 0000 0000 0000 0000

16进制表示: 0x4104 0000

 

尾数部分:经过第一步转换后 8.25等于 1.00001 * 2的三次方(指数是3)

尾数直接从前往后放所以尾数是:000 0100 0000 0000 0000 0000

 

指数部分:

首位表示小数点移动方向

向左移动则为1,向右为0

 

指数部分简单方法:

不论左移还是右移。一律把指数 +127 然后取2进制

左移了三次,指数为3,3的二进制是11,但是这里要减去1

所以指数部分为 1000 0010

浮点类型的精度

  1. float和double的精度是由尾数的位数来决定的;

  2. float : 2^23 = 8388608 一共7位,这意味着最多能有7位有效数字;

  3. double : 2^52 = 4503599627370496 一共16位,这意味着最多能有16位有效数字。

posted @ 2023-04-02 18:00  bonelee  阅读(148)  评论(0编辑  收藏  举报