浮点数原理探究

一、文章来由

今天听到实验室有人问道浮点数的实现机制,之前刚好研究过原码、反码、补码、移码的关系,而这类问题很底层,一般容易忽视。干脆打破沙锅问到底,彻底搞清楚这个问题并留下证据,于是就有了这篇博文。

二、原码、反码、补码、移码

不要背复杂的公式,简记如下,都是用的最简单易懂的语言:
特别注意:首先要说明的是,正数的原、反、补码都一样;0的原码跟反码都有两个,因为这里0被分为+0和-0。

原码:

即直接的二进制表示,最高位为符号位:正数为0,负数为1 例如: X=+101011 , [X]原= 00101011
X=-101011 , [X]原= 10101011 位数不够的用0补全。

反码:

正数的反码与其原码相同;负数的反码是对其原码逐位取反,但符号位除外。 例如:X=-101011 , [X]原= 10101011,[X]反=11010100

补码:

正数的补码与其原码相同;负数的补码是在其反码的末位加1。
例如:X=-101011 , [X]原= 10101011,[X]反=11010100,[X]补=11010101
注:补码还有一种速算法,符号位不变,从原码低位开始从右向左数,直到遇到第一个1,保留这个1,以后的按位取反

PS:0的补码是唯一的,如果机器字长为8那么 [0]补=00000000

移码【最简单】:

不论正负数,只要将其补码的符号位取反即可。

例如:X=-101011 , [X]原= 10101011 ,[X]反=11010100,[X]补=11010101,[X]移=01010101

三、从定点到浮点

首先定点到浮点是一个飞跃,这里面的内容其实可以很简单也可以很复杂。我们一般说的整数都是定点整数,即小数点固定最后一位。但是整数既可以是整数,也可以是浮点数,例如255 是整数,而255.0 则是浮点数。

什么是浮点数?这需要从小数的表示讲起:

3.1 浮点数的表示

计算机中一个任意进制数 N 可以写成
小数表示法
m :尾数,是一个纯小数。
e :浮点的指数, 是一个整数。
R :基数,对于二进计数值的机器是一个常数,一般规定R 为2,8或16

尾数主要是决定有效位,阶码主要表示位数(小数点位置)。
阶码:用定点整数形式表示,指明小数点在数据中的位置,决定了浮点数的表示范围,常用补码或者移码表示
尾数: 决定了浮点数的数值精度,是定点小数,用补码表示,也决定了整个浮点数的符号

机器字长一定时,阶码越长,表示范围越大,精度越低
浮点数表示范围比定点数大,精度高

画一个简单易懂的表格:
c语言float型数表示

符号位(S)阶码(E)尾数(M)
1823

浮点数表示范围如下图:

浮点数表示范围

例:
8位定点小数可表示的范围
0.0000001 — 0.1111111
1/128 — 127/128

设阶码2位,尾数4位
可表示2-11*0.0001 — 211*0.1111
0.0000001 — 111.1

设阶码3位,尾数3位
可表示2-111*0.001 — 2111*0.111
0.0000000001 — 1110000

注:float和double的范围是由指数的位数来决定的。
float的指数位有8位,而double的指数位有11位,分布如下:
float:
1bit(符号位) 8bits(指数位) 23bits(尾数位)
double:
1bit(符号位) 11bits(指数位) 52bits(尾数位)

这里写图片描述

3.2 浮点数的规格化

规格化目的:
(1)为了提高数据的表示精度
(2)为了数据表示的唯一性
(3)尾数为R进制的规格化: 绝对值大于或等于1/R

二进制原码的规格化数的表现形式:
正数 0.1xxxxxx
负数 1.1xxxxxx

补码尾数的规格化的表现形式:尾数的最高位与符号位相反:
正数 0.1xxxxxx
负数 1.0xxxxxx

这里写图片描述

【32位浮点数,IEEE754采用127做阶码的偏移量】
IEEE754规定这个偏移量为2^(e-1)-1,e为存储指数的位元的长度,在32位浮点数中存储指数的域有8位因此偏移量位2^(8-1)-1=127。这里根据标准,并没有使用移码作为阶码
**注意IEEE754中的移码和通常用的移码不相同,IEEE754用的是127移码,即在原数上加127
而不是通常的128移码(也就是所说的补码符号位取反)**

例1:

这里写图片描述

如果反过来求就是,
例2
这里写图片描述

例3
这里写图片描述

3.3 移码的来由

一个很有意思的问题
说了这么多,由移码当阶码,到移码-1到阶码,都不知道为什么,现在就来看看。
根据百度百科移码上说的:

移码(又叫增码)是符号位取反的补码,一般用做浮点数的阶码,引入的目的是为了保证浮点数的机器零为全0。

原因是:

用补码表示阶码的时候,当阶码无限小,产生了下溢的时候,阶码变成了0,那么这个浮点数的值变为了1。
而实际上这个数是无限接近于零的。那么我们就需要取出其中的 “-0“ 值作为机器零。

详细解释如下:
因为浮点数的表示是1.s * (2 ^ P), 所以浮点数0实际上是取无限接近于0,而不是其数值上确实得等于0

0的表示实际上是1.0 * (2 ^ -128),其中-128是阶码能表示的最小数

于是问题来了,如果用补码表示, -128实际上是10000000, 那么浮点数的0其数值就不能等于0. 所以采用移码.

但是IEEE754标准采用的是127移码,即在0的基础上加上127作为0,于是阶码表示范围是-127 - 128,而不是通常的-128 - 127

文章也基本上要告一段落了,这些应该已经可以对付日常理解,如果需要更深刻的理解,就需要查阅更多资料,如果博文中有不当的内容,欢迎批评指正,也欢迎讨论

附:
c++中,合法的浮点数表示形式:
(1)十进制小数形式。他有数字和小数点组成,必须有小数点。例如(123.)(123.0)(.123)。
(2)指数形式。如123e3。字母e(或E)之前必须有数字,e后面的指数必须为整数。
(3)规范化的指数形式里面,小数点前面有且只有一位非零的数字。如1.2345e8

详细了解补码,要看我这篇:补码与模

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值