前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >单精度浮点数的取值,表示以及相关

单精度浮点数的取值,表示以及相关

作者头像
用户1148523
发布2019-05-27 19:56:29
2.8K0
发布2019-05-27 19:56:29
举报
文章被收录于专栏:FishFish

取值范围及精度

可以表示的范围为±3.40282 * 10^38(1.1111…1×2^127)即:

0-11111110-11111111111111111111111(23个1)

float最大值
float最大值

单精度浮点数可以表示1.175 * 10-38(1.00…0×2^-126)的数据而不损失精度。

0-00000001-00000000000000000000001(22个0,最后一位是1)

float最精确值
float最精确值

浮点数最小能表示的是当阶码都是0时,表示2^-126*0.fractionbits

这里写图片描述
这里写图片描述

ps:以上图片是从 这个网址 截取。

表示方式

  1. 如果指数位全零,尾数位是全零,那就表示0
  2. 如果指数位全零,尾数位是非零,就表示一个很小的数(subnormal),计算方式 (−1)^signbit × 2^−126 × 0.fractionbits(注意这里是0.fractionbits,应该是为了和阶码是-126的时候做出区分,其实也就是比-126的时候能表示的数更小了)
  3. 如果指数位全是1,尾数位是全零,表示正负无穷
  4. 如果指数位全是1,尾数位是非零,表示不是一个数NAN
  5. 剩下的计算方式为 (−1)^signbit × 2^(exponentbits−127) × 1.fractionbits

补码

到底什么是补码,一直到看了 这个知乎回答 之前,我对补码的概念就是反码加一,而且也没有想过到底为什么这样,有什么意义,看完之后才有些恍然大悟。

首先,第一个问题,补码是用来做什么的?

补码是用来方便ALU做减法运算的,因为补码是没有符号的,减一个数相当于加这个数的补码。

所以,第二个问题就是,为什么减一个数相当于加一个数的补码呢?

在回答这个问题之前,首先问一下,如果补码就是简单的反码加一为什么要叫补码,为什么不直接叫反码加一呢,这里就要提出一个概念,叫补数

钟表的例子

这个例子就是补数的直观理解,先假定表盘就表示0-11点,然后现在指针指向2点,如果我想将指针拨到3点有两个办法,第一个是顺时针拨1个格,第二个是逆时针拨11个格,在一个满刻度是12的表盘上,这两个的效果是一样的。抽象来讲,2 - 1 = 2+11

这是为什么呢,这就有个的概念,模,当然数学上有抽象解释,我们这里就可以理解成数的表示极限大小,这里的模就是12,而对于十进制的两位数来说,模就是100。

继续回到 2 - 1 = 2+11 这个问题,因为模是12,所以在这个模下,每个数有其补数,补数的意思就是模减其本身。这里1的补数就是 12 - 1 = 11.而减去一个数,就相当于加上这个数的补数,所以我们得到2 - 1 = 2+11。

再以十进制两位数为例,90 - 10 = 80.10的补数是100-10=90,所以 90 -10 = 90 + 90(忽略百位,因为这里只有两位)。到这里总结一下,一个数的补数 = 模 - 这个数,一个数 - 另一个数 = 一个数 + 这个数的补数

但是如果是10 - 90 怎么办,难道10 - 90 = 10 + 10,-80难道等于20?没错!我们想用数表示-80,却不让加负号,那就直接让-80 = 20。所以,一个负数就用它绝对值的补数来表示

那么,现在的问题是,一个数既可以表示正数又可以表示负数,比如20既可以表示-80也可以表示20,那咋整,就规定0~99,0~49表示整数,50~99表示负数,90就代表-10这种。

实际上

对于浮点数的阶码是8位二进制数,其表示的极限是256(11111111表示255),所以模就是256,根据上面讲过的,将表示范围一分为二:00000001~01111111表示正数,10000000~11111110表示负数(全0和全1有特殊含义)。这样结合上面讲的知识就显而易见了,以10000000为例,256 - |x| = 128.所以表示的x=-128

移码

虽然补码解决了负数的问题,但是补码还是有一定的缺陷,就是比较大小不方便,而进行浮点数运算的时候,有一步是对阶,也就是比较阶码的大小然后再获得浮点数实际大小。为了方便比较大小,浮点数使用移码表示阶码。

移码,顾名思义,就是当前码通过(在坐标轴上)移动之后获得的码,而移动的距离称为偏置(bias)。

为什么移动之后就方便比较大小呢,具体如下图:

不用移码的时候数轴是这样的:

正常补码
正常补码

上面是实际的数,而下面是这些数代表的数,也就是上面讲的,254代表-2之类的。

如果我们使得下面的数向右移动一格:

移动一位
移动一位

可以看到,现在254代表的是-3了,再移动一格呢:

移动两位
移动两位

依次类推,可以一直推到255代表的是最大的正数,这样,就可以直接通过比较码的大小来判断实际值的大小了,是不是很方便呢

不过这里没有考虑全0和全1的情况,但是大概原理就是这样了。

ps:为什么为什么用127做偏置而不是128:据说是为了让数的表示范围对称( 原文 ),但是感觉比较牵强而且也不比用128时对称

半精度与单精度的转换

主要是最近在研究f16和f32的转换才看了上面一堆东西,正题是f16和f32是怎么转换的。

这个就简单了,由上面的知识可以推知,half的表示范围最大也就到65535,而float则很大,因此当half往float转换时,就是指数位转换到指数位,小数位低13位补零。当然考虑到阶码是移码,因此要-15+127才是最终的阶码。同理,从float转换到half也是,阶码-127+15,然后砍掉小数位后13位即可。

这里要注意,如果float原本表示的数超过了half的表示范围,那么转换成的half就是阶码全是1的NaN。

cite:Van Der Zijp J. Fast half float conversions[R]. Working paper, 2012ftp://www. fox-toolkit.org/pub/fasthalffloatconversion. pdf, 2008.

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2018年06月12日,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 取值范围及精度
  • 表示方式
  • 补码
    • 钟表的例子
      • 实际上
      • 移码
      • 半精度与单精度的转换
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档