C语言学习4 数据类型之浮点的但双精度区别



前面我们已经了解整形一类的数据类型。

这次我们就说说浮点类型

要先记住一点:

整数、正数不一样哦

类型说明字节
float浮点型单精度数据类型,含有小数点的数字就是它4字节
double浮点型双精度数据类型,主要双精度可以放更大的浮点值8字节

上方表格,已经表明了浮点类型都有哪几个。

有没有注意到,一个是

单精度

另一个是

双精度

那么,浮点类型,是以单双精度来区别吗?

我们先来说说

float

float是4个字节,也即是32位。

但它有一个符号位,在32位的最左边,也叫最高位。

所以在没有unsigned的加持下,它的有效数据位是

31位。

你说,我在听

那float在内存,它是怎么展示的?

列个内存为出来:

float在内存的存放为分为1个符号位、8个指数位、23个尾数位
double在内存的存放分为1个符号位、11个指数位、52个尾数位

了解他们大概的位置后,我们再说说

什么是符号位

在没有unsigned的加持下,都有一个符号位。

0代表正数 1代表负数

什么是指数

在数学中,指数是表示幂运算的一种方式。一个指数是一个数字,它表示另一个数(底数)被乘以自身多少次。指数通常用上标的形式表示,写在底数的右上方。

懵逼

没听懂是把,我就用float的8个指数位来解释下。

我们内存讲究二进制,也就是以2次幂来计算。

float有8个指数,也就是有8个次幂。

那么2的8次幂的表示就是。

28=256。

但我们的8个指数位不能全部打开,因为浮点的

内存标准

不一样。

浮点类型的标准是按

IEEE 754 标准

来做内存运算的。

啥标准?

IEEE 754 标准不知道的话,百度下。

也就是指数位在float开辟的32位里面是独立的,它也有自己的符号位

如果你8个指数位全开,就会变成负数。也就成了-128.

所以为了表示正数、负数和零,以及保留一位用于表示特殊情况(如无穷大和非数值),需要对指数进行偏移,确保它可以表示负数。因此,选择的偏移值是

28-1−1=27−1=127

这个2的7次幂-1后面说到内存位运算就会明白,跟二进制位运算有关,想知道可以自己查下资料。

127这个数字要记住,我们还需要他运算。

什么是尾数位

尾数是一个二进制小数。在单精度浮点数中,通常占23位;在双精度浮点数中,通常占52位。

这一句就能很明白的说明,为什么双精度更精确了把,你用Π=3.14往后算,单精度只能记住23位尾数,而双精度可以记住小数点更后面的52个尾数。

继续继续

比如说,我们在编译器输入一个浮点数:

float num=-123.1234f;

那么-123.1234(注意看,有个负数)是怎么放入num的内存里呢?

如果它是正数,符号位为

0 00000000 00000000000000000000000

如果是负数,则:

1 00000000 00000000000000000000000

以这样的方式展示在内存。

重要的开始了:

符号我们已经记录在内存了,这个不管了。我们看123.1234

将123.1234拆开分为

整数部分123

小数部分0.1234

看清楚了,然后将整数123转为2进制。不懂转的,直接用二进制转换工具转,得出:

1111011

这样整数部分的二进制就得出

1111011

小数位是0.1234,就只要将0.1234用

短乘法 取整

让小数部分变成整数,没有小数点就结束,那就得出:

0.1234*2=0.2468这个得出了第一个二进制0(1)

括号里的1是我们用来计算算了几次,这个不用记。

取小数点左边的值,但还没有整数,就继续算。

0.2468*2=0.4936取0再继续(2)

0.4936*2=0.9872取0再继续(3)

0.9872*2=1.9744取1(4)

到这个位置出现了1,就取整数1。接下来不能再用1.9744*2了,而是取了个1之后,就要变成0.9744*2。

以后都是这样。

但还未变整数,再继续运算。

0.9744*2=1.9488取1再继续(5)

0.9488*2=1.8976取1再继续(6)记住,取1之后就不能再用1.8976*2。

0.8976*2=1.7952取1再继续(7)

0.7952*2=1.5904取1再继续(8)

0.5904*2=1.1808取1再继续(9)

0.1808*2=0.3616取0再继续(10)

0.3616*2=0.7232取0再继续(11)

0.7232*2=1.4464取1再继续(12)

0.4464*2=0.8928取0再继续(13)

0.8928*2=1.7856取1再继续(14)

0.7856*2=1.5712取1再继续(15)

0.5712*2=1.1424取1再继续(16)

0.1424*2=0.2848取0再继续(17)

0.2848*2=0.5696取0再继续(18)

0.5696*2=1.1392取1再继续(19)

0.1392*2=0.2784取0再继续(20)

0.2784*2=0.5568取0再继续(21)

0.5568*2=1.1136取1再继续(22)

0.1136*2=0.2272取0(23)

到这了,我们不再继续算了,因为单精度尾数就23位,得不出整数值,就只算到在这。

我们现在得出小数的二进制是:

00011111100101110010010

指数和尾数已经转化完毕,接下来就是再把他们合为一体得出:

1111011.00011111100101110010010

说的什么鬼

先别懵,别以为浮点数就是这样,还没完。

如果真的很懵,你在返回去看一遍。

不然接下来你会更懵。

接下来就是

科学计算法

不知道科学计算法,就百度一下再来看

将得到的

1111011.00011111100101110010010

二进制科学计算法是小数点往左移,变成

1.11101100011111100101110010010

小数点移动了6位,就是得到了6个真实指数。

还记得我们说过的指数位吗?

float的指数位根据

IEEE 754 标准

偏移值是

127

就将127+6=

133

再把133转为2进制得出:

10000101

现在已经得到8个IEEE 754 标准规定的指数位二进制了,我们放在内存里就是:

1 10000101 00000000000000000000000

现在符号位有了,指数位有了。接下来就是尾数位了,尾数位就比较简单了。

尾数位就是刚才科学计算法得出的

1.11101100011111100101110010010

这个二进制,把小数点和小数点向左的数字都去掉,留下

11101100011111100101110010010

只要23位就是

11101100011111100101110

这部分就是尾数位了。

现在我们放在内存就是:

1 10000101 11101100011111100101110

不够23位就右边加0填满23位,如果够23位就直接放进去。

没看懂,再看一遍。

那这串二进制,他们是怎么展现到屏幕给我们看的呢?

那就要看你是用整数提取符 %d去提取,还是浮点提取符%f提取了。

如果是整数提取符,数值肯定是错的。

但你要先问你自己,你定义了一个float数据类型,他在内存开辟了有指数和尾数的内存位,你用整数提取符提取,就是你自己错了。

整数的数据类型标准和浮点数的数据类型标准不一样

只有%f才能解释知道指数位和尾数位。

而且

%f浮点数提取符和整数提取符不一样,%f它是IEEE 754 标准 它只认指数位和尾数位。

不信你可以这个代码试一试:

int num=-1231234;
printf("%f",num);

看看浮点提取符能不能提取整数。

%f会查不到指数和尾数位的开关。

所以 %f 提取不到指数位和尾数位的话,那么它给你屏幕输出出的值要么是0,要么是错误的值。

这时有人会问我:

1 10000101 11101100011111100101110

这串二进制转换出来的值也不是-123.1234呀。

如果你二进制直接转十进制,得出的数字当然是错的。

再强调一遍

IEEE 754 标准

IEEE 754 标准

IEEE 754 标准

因为浮点数都说了,它有它自己的一个标准,就是:

IEEE 754 标准

这个标准里用了一个更有紧凑性、可读性和位操作性的执行方式来展现。

就是中间过程转了个

十六进制

所以1 10000101 11101100011111100101110 这个二进制,你要先用进制计算器转为十六进制,在转为十进制,就能得出我们所计算的这个值了。

原来如此

double

数据类型呢?

它也一样。

我们说了,它的精度更准确,因为它的

指数位是11位,去掉符号位是1024-1=

1023+N指数值

而它的尾数位是

52个尾数位

所以算起来,double的浮点数值小数点值更精确。

计算方法与float一样。

但平常我们不怎么用double。

因为float 127+N的指数值就已经很大了。

听懂掌声


C语言 debian 戴戴 新闻 日记 编译器 说说

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注