浮点数c语言,C语言浮点数运算

C语言标准C89里规定了3种浮点数,float型、double型和long double型,常见的浮点型长度为float型占4个字节,double型占8个字节,long double型长度要大于等于double型,下面将以float型为例进行介绍,double型和long double型只是比float型位数长,原理是一样的 。

float型可以表示的十进制范围是-3.402823466e38~3.402823466e38,而作为同为4个字节的定点数却只能表示-2147483648~2147483647的范围,使用同样的内存空间,浮点数却能比定点数表示大得多的范围,这是不是太神奇了?既然浮点数能表示这么大的范围,那么我们为何不使用浮点数来代替定点数呢?先不说浮点数实现起来比较复杂,有些处理器还专门配置了硬件浮点运算单元用于浮点运算,主要原因是浮点数根本就无法取代定点数,因为精度问题。鱼和熊掌不可兼得,浮点数表示了非常大的范围,但它失去了精度。

ANSI/IEEE Std 754-1985标准

IEEE 754是最广泛使用的二进制浮点数算术标准,被许多CPU与浮点运算器所采用。IEEE 754规定了多种表示浮点数值的方式,下面介绍32位二进制的float浮点类型。它被分为3个部分,分别是符号位S(sign bit)、指数偏差E(exponent bias)和小数部分F(fraction),这三部分都是对应二进制码的。

36398750_1.jpg

浮点表示的一般形式为(科学技术法规则):R=(S) * (1 + F) * 2e (R:实数       S:正负符号      F:小数部分     e:指数,不同于指数偏差)。

符号位S:占1位,0代表浮点数是正数,1代表浮点数是负数。

指数偏差E:占8位,范围是0~255,e = E - 127,e为正值表明转换成二进制码后,按科学计数法表达时向左移动了e位, 负值表明向右移动了e位。

小数部分F:占23位,实际上是将浮点数转换成二进制码,再按科学计数法表达,将其小数部分存在F上,由于二进制码按科学计数法表达后,只要值不为0,整数部分就必然为1,所以可以省略整数部分。

例如,3.75的二进制码为11.11,将该二进制码按科学计数法表达为1.111,则向左移动了1位,即e=1,E=e+127=128,F记录的便是小数部分,实际为111000...000。

下面介绍一下小数部分转换为二进制码的方式。类似于整数的形式(如7 = 22 + 21 + 20),小数部分的转换形式为2-1、2-2、2-3、2-4......,例如0.5 = 2-1,即二进制码为0.1,0.05 = 2-5 + 2-6 + 2-9 + 2-10 + 2-13 + 2-14 +...... (可无限循环),即二进制码为0.00001100110011......。如果都以16位计,那么7的二进制码为0000000000000111,0.5的二进制码为0.1000000000000000,0.05的二进制码为0.0000110011001100。这是如何换算出来的呢?且看下面的算法便知:

换算0.5,乘法结果初始为0.5,所有乘数为2,每次用乘法结果 * 乘数,得到新的乘法结果,结果中的整数部分被提取出来,剩余的小数部分继续参加下一次乘法运算,直到剩余小数部分为0,或者无终点(无限循环)。根据表格中的整数部分可知,二进制为0.1。

整数部分

乘数

乘法结果

剩余小数部分

0.

2

0.5

0.5

1

1

0

结束

换算0.05,乘法结果初始为0.05,所有乘数为2,每次用乘法结果 * 乘数,得到新的乘法结果,结果中的整数部分被提取出来,剩余的小数部分继续参加下一次乘法运算,直到剩余小数部分为0,或者无终点(无限循环)。根据表格中的整数部分可知,二进制为0.00001100110011......。

整数部分

乘数

乘法结果

剩余小数部分

0.

2

0.05

0.05

0

2

0.1

0.1

0

2

0.2

0.2

0

2

0.4

0.4

0

2

0.8

0.8

1

2

1.6

0.6

1

2

1.2

0.2

0

2

0.4

0.4

0

2

0.8

0.8

1

2

1.6

0.6

1

1.2

0.2

无限循环

例1:float型浮点数125.5转化成32位二进制浮点数。

125.5的整数和小数部分的二进制码分别为1111101和0.1,于是125.5的二进制码为1111101.1,按科学技术法写为1.1111011*26,即向左移6位,则e=6,E=e+127=133,133的二进制码为10000101。而1.1111011把整数部分的1去掉后,剩下小数部分为1111011,之后补0至23位,构成F。所以125.5的32位二进制浮点数为:

0  10000101  11110110000000000000000

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

类似的,0.5的二进制码为0.1,按科学技术法写为1.0*2-1,即向右移1位,则e=-1,则E=e+127=126,126的二进制码为01111110。而1.0把整数部分的1去掉后,剩下小数部分为0,之后补0至23位,构成F。所以0.5的32位二进制浮点数为:

0  01111110  00000000000000000000000

几个特殊的情形

E=0,F=0时,表示浮点数0,此时浮点数受S影响,表现出+0和-0两种0,但数值是相等的。比如二进制数0x00000000表示+0,二进制数0x80000000表示-0。

E=0,F不等于0时,浮点数为(S) * (F) * 2e,注意e为-126,而不是0-127=-127,而且F是0.xxx格式而不是1.xxx格式,比如0x00000001的浮点数为2-126*2-23=1.4012984643248170709237295832899e-45,而不是20-127*(1+2-23)。E从0变为1,不会产生增加2倍的关系,而是计算公式改变了(恢复正常公式)。

E=255,F不等于0时,表示非数值,也就是说是非法数,例如0x7F800001。

E=255,F=0时,表示无穷大的数,此时浮点数受S影响,例如0x7F800000表示正无穷大,0xFF800000表示负无穷大。做除法时,如果除以0时,结果将被记作0x7F800000。

浮点数的精度

从前文中可以看到,1.xxx这类浮点数中,F部分最小的是2-23,对应的十进制数为1.00000011920928955078125,可以精确表示到小数点后23位,但是一些C语言书上却说float型的有效位只有6~7位,这是为什么呢?原因在于二进制小数与十进制小数没有完全一一对应的关系,二进制小数相比十进制小数来说,是离散而不是连续的,我们来看看下面这些数字:

二进制小数    十进制小数

2-23       1.00000011920928955078125

2-22       1.0000002384185791015625

2-21       1.000000476837158203125

2-20       1.00000095367431640625

2-19       1.0000019073486328125

2-18       1.000003814697265625

这里只需要关注F,上面列出了1.xxx这类浮点数中的6个最小的二进制小数,及其对应的十进制数。可以看到使用二进制所能表示的最小小数是1.00000011920928955078125,其次是1.0000002384185791015625,这两个数之间是有间隔的,如果想用二进制小数来表示8位有效数(只算小数部分,小数点前面的1是隐藏的默认值)1.00000002、1.00000003、1.00000004......这些数是无法办到的,而7位有效数1.0000001可以用2-23来表示,1.0000002可以用2-22来表示,1.0000003可以用2-23+2-22来表示。从这个角度来看,float型所能精确表示的位数只有7位,7位之后的数虽然也是精确表示的,但却无法表示任意一个想表示的数值。

但还是有一些例外的,比如说7位有效数1.0000006这个数就无法用F表示,这也表明二进制小数对于十进制小数来说相当于是离散的,刚好凑不出1.0000006这个数,从这点来看float型所能精确表示的位数只有6位。因此float型的有效位数是6~7位,但这个说法应该不是非常准确,准确来说应该是6位,C语言的头文件中规定也是6位。对于一个很大的数,例如1234567890,它是由于指数E系数而被放大了的,但它的有效位仍然是F所能表示的6~7位有效数字。1234567890用float表示后为1234567936,只有高7位是有效位,后3位是无效的。int型可以准确的表示1234567890,而float浮点数则只能近似的表示1234567890,精度问题决定了float型无法取代int型。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值