目录结构:

contents structure [-]

IEEE 754(Institute of Electrical and Electronics Engineers)在1985年发布,该标准是为了统一规范浮点数的存储。

1.浮点数的存储过程

在IEEE 754标准中浮点数由三部分组成:符号位(sign bit),有偏指数(biased exponent),小数(fraction)。浮点数分为两种,单精度浮点数(single precision)和双精度浮点数(double precision),它们两个所占的位数不同。

单精度浮点数(共32位):
1个符号位
8个指数位
23个小数位

双精度浮点数(共64位):
1个符号位
11个指数位
52个小数位

接下来笔者以单精度浮点数0.15625讲解浮点数的存储过程:
0.1562510转化为二进制就是0.001012,然后将该数写成科学计数法(scientific notation),根据IEEE 754的规定,小数点的左边只能有一个1,所以最终的科学计数法形式是:

0.1562510 = 0.001012 = 1.012 * 10-3

然后就可以得到小数部分为.012,指数部分为-3。

最终在内存中的存储结果就是如下图:

符号位(sign):0,因为该数是正数(1表示负数)。

有偏指数(biased exponent):-3 + 偏移量(bias),在单精度浮点数中偏移量是127,因此127+(-3)=124,所以偏移指数是124。在双精度浮点数中偏移量是1023,因此偏移指数是1020。

小数(fraction):.010000000000000000000002

在上面已经展示了浮点数的存储过程,接下来再仔细说一说有偏指数,还是拿单精度浮点数来说吧! 在单精度浮点数中,有8位可以用来存储指数(范围就是:0~255),那么怎么表示负的指数呢?IEEE 754标准的制定者为了解决这个问题,约定了指数偏移量(单精度的偏移量是127),指数值要在加上偏移量后才能进行存储,这样就能表示指数的正负值了。通常情况下,如果存储的值大于偏移量,那么就意味着指数是正的;如果存储的值小于偏移量,那么就意味着指数是负的;如果存储的值等于偏移量,那么就意味着指数为0。

下面的对应关系,显示了有偏指数代表的各种含义:

0 == 特殊情况:零(zero) 或 次正规数(subnormal)
1 == 2 ^ -126
...
125 == 2 ^ -2
126 == 2 ^ -1
127 == 2 ^ 0
128 == 2 ^ 1
129 == 2 ^ 2
...
254 == 2 ^ 127
255 == 特殊情况:无穷大(infinity) 或 非数值(NaN)

1.1 次正规数(Denormalized Number)

IEEE 754的设计者注意到,除了0.0所有的二进制的科学计数法都有一个1在小数点的左边。在上面也提到过,在写成标准的科学计数法的形式后,小数点的左边只能有一个1。
比如:
25.010 == 110012 = 1.10012 * 24
0.62510 == 0.1012 = 1.012 * 2-1
小数点的左边都是以一个1开始的,为了节约内存,它们规定:所有数在小数点左边默认有一个1。

按照这个规定的话,那么能够表示的最小正数就是:
0 00000001 000000000000000000000012 = 1.000000000000000000000012 * 2-126

如果指数全为0,只能表示数字0的话,那么表示小数位的23位就没有利用起来。于是IEEE754的设计值,规定了一种新的数 次正规数(Subnormal Number Or Denormalize Number)。规定如下:
如果指数位全为0的话,那么在科学计数法中小数点的左边就默认为一个0。这样的数,就被称为次正规数。

在次正规数中所有的偏移指数位都是0,于是规定在单精度浮点数中指数应该为-126(并非-127),在双精度浮点数中指数应该为-1022(并非-1023)

所以最小的正数就应该是:
0 00000000 000000000000000000000012 = 0.000000000000000000000012 * 2-126

1.2 零(zero)

数值0被特殊表示:

符号位(sign) = 0或1
有偏指数(biased exponent) = 0
小数(fraction)= 0

0的内存二进制码为:

0 00000000 00000000000000000000002
1 00000000 00000000000000000000002

1.3 非数值(NaN)

有一些算数操作是非法的,比如对负数开根号。这类非法操作被称为浮点数异常(floating-point exception),异常结果由特殊字符NaN(Not a Number)表示。

符号位(sign) = 0或1
有偏指数(biased exponent)= 所有位都是1
小数(fraction) = 除了所有位都是0的数(因为所有为0,表示无穷大)

小数位只要不全为0,就表示非数值。
0 11111111 111111111111000000100002

1 11111111 111111111111000000100002

1.4 无穷大(infinity)

无穷大有两种,正无穷大(Positive Infinity)和负无穷大(Negative Infinity)。

符号位(sign) = 0表示正无穷大,1表示负无穷大。
有偏指数(biased exponent) = 所有位都是1
小数(fraction) = 所有位都是0.

正无穷大
0 11111111 000000000000000000000002
负无穷大
1 11111111 000000000000000000000002

2.除数为0.0会发生什么

如果计算机是采用的IEEE 754的标准(绝大部分计算机都是采用该标准)。那么当除数为0.0时,会发生不可预期的行为(注意程序不会中断)

#include <iostream>
#include <limits>
int main(){
//is_iec559是否支持IEC-559 / IEEE-754标准
std::cout << std::numeric_limits<float>::is_iec559 << std::endl;
std::cout << (1.0 / 0.0) << std::endl;
std::cout << (-1.0 / 0.0) << std::endl;
std::cout << (0.0 / 0.0) << std::endl;
return ;
}

程序的输出结果是:

1
inf
-inf
-nan

3.浮点数的范围

在学习过上面的知识后,我们清楚了IEEE 754中浮点数在内存中的表示形式,我们也知道0(zero)是最小的(这里和下面只讨论非负数),次正规数(Denormalized Number)的表示范围比0大,正规数(normalized Number)表示的范围比次正规数大。

下面清楚的显示了一些范围和数值:

0 00000000 000000000000000000000012 = 0000 000116 = 0.12 × 2-22 × 2-126  =  2−126 × 2−23 = 2−149 ≈ 1.4012984643× 10−45

(最小的次正规数,smallest positive subnormal number)

0 00000000 111111111111111111111112 = 007f ffff16 = 0.111111111111111111111112 * 2-126  =  2−126 × (1 − 2−23) ≈ 1.1754942107 ×10−38

(最大的次正规数,largest subnormal number)

0 00000001 000000000000000000000002 = 0080 000016 = 1.02 × 21-127 = 2−126 ≈ 1.1754943508 × 10−38

(最小的正正规数,smallest positive normal number)

0 11111110 111111111111111111111112 = 7f7f ffff16 = 1.111111111111111111111112  × 2254-127 =  2127 × (2− 2−23) ≈ 3.4028234664 × 1038

(最大的正正规数,largest normal number)

0 01111110 111111111111111111111112 = 3f7f ffff16 = 1.111111111111111111111112 × 2126-127 = 1 − 2−24 ≈ 0.9999999404

(比数值1小的最大数,largest number less than one)

0 01111111 000000000000000000000002 = 3f80 000016 = 1.02 × 2127-127  = 1.02 × 20 = 1

(数值1,one)

0 01111111 000000000000000000000012 = 3f80 000116 = 1.000000000000000000000012 × 2127-127 = 1 + 2−23 ≈ 1.0000001192

(比数值1大的最小数,smallest number larger than one)

1 10000000 000000000000000000000002 = c000 000016 = −2

0 00000000 000000000000000000000002 = 0000 000016 = 0

1 00000000 000000000000000000000002 = 8000 000016 = −0

0 11111111 000000000000000000000002 = 7f80 000016 = infinity(正无穷)

1 11111111 000000000000000000000002 = ff80 000016 = −infinity(负无穷)

0 10000000 100100100001111110110112 = 4049 0fdb16 ≈ 3.14159274101 ≈ π ( 圆周率,pi )

0 01111101 010101010101010101010112 = 3eaa aaab16 ≈ 0.333333343267 ≈ 1/3

x 11111111 100000000000000000000012 = ffc0 000116 = qNaN (on x86 and ARM processors)

x 11111111 000000000000000000000012 = ff80 000116 = sNaN (on x86 and ARM processors)

通常我们所说的浮点数的范围,都是指的正规数的存储范围。

Level Width Range at full precision
Single precision 32bits ±1.18×10−38 to ±3.4×1038
Double precision 64 bits ±2.23×10−308 to ±1.80×10308

4.浮点数的精度

在单精度浮点数中的二进制小数位有23个,所能表示2^23个数,那么只需要换算成在10进制下能够表示相同个数的位数,就可以得到精度了。
10n = 223
10n = 8388608
106 < 8388608 < 107
所以但精度浮点数的精度为6位,同理也可以得到双精度浮点数的精度为15位。

注意:精度为6位,并不是表示所有小于6的数都可以被精确存储,比如0.9。因为这个精度是由二进制的精度位数计算而来的。

所以浮点数的相等判断中,只需要判断他们的差值小于精度就可以了。

#include <stdio.h>      /* printf */
#include <math.h> /* fabs */ int main ()
{
float f1 = 0.007;
float f2 = 0.009; int res = ( fabs(f1-f2) < 1e- );
printf ("f1 == f2 is : %s\n",res?"true":"false");
return ;
}

输出结果:

f1 == f2 is : false

5.参考文献

Single-precision floating-point format_Wikipedia
IEEE 754-1985_Wikipedia
What is a subnormal floating point number?
What is a “bias value” of floating-point numbers?

【算法】解析IEEE 754 标准的更多相关文章

  1. python 警惕 IEEE 754标准

    双精度浮点数格式,即IEEE 754标准 >>> 0.1+0.2 0.30000000000000004 >>> (0.1+0.2)==0.3 False > ...

  2. 打印一个浮点数组,会输出字符串"Hello, world“ & 浮点数的二进制表示(IEEE 754标准)

    #include <stdio.h> #include<stdlib.h> int main() { float a[3] = { 1143139122437582505939 ...

  3. IEEE 754标准--维基百科

    IEEE二进制浮点数算术标准(IEEE 754) 是20世纪80年代以来最广泛使用的浮点数运算标准,为许多CPU与浮点运算器所采用.这个标准定义了表示浮点数的格式(包括负零-0)与反常值(denorm ...

  4. 基于 IEEE 754 标准的 单精度浮点数计算方式 (未完成)

    def dec2bin(dec): if dec < 0: s = ' dec = dec * (-1) else: s = ' e = 127 dec = float(dec) r = int ...

  5. IEEE 754标准

    IEEE 754-1985 was an industry standard for representing floating-point numbers in computers, officia ...

  6. IEEE 754二进制浮点数算术标准

    可能很多人都遇到过浮点数精度丢失的问题,下面以JavaScript为例. 1 - 0.9 = 0.09999999999999998 纳尼,不应该是0.1么,怎么变成0.099999999999999 ...

  7. IEEE二进制浮点数算术标准(IEEE 754)

    整理自IEEE 754 IEEE二进制浮点数算术标准(IEEE 754)是20世纪80年代以来最广泛使用的浮点数运算标准,为许多CPU与浮点运算器所采用.这个标准定义了表示浮点数的格式(包括负零-0) ...

  8. IEEE 754浮点数表示标准

    二进制数的科学计数法 C++中使用的浮点数包括采用的是IEEE标准下的浮点数表示方法.我们知道在数学中可以将任何十进制的数写成以10为底的科学计数法的形式,如下 其中显而易见,因为如果a比10大或者比 ...

  9. 【Python】解析Python的标准数据类型

    目录结构: contents structure [-] 数值(Number) 数值类型 类型转化 Python中的Decimal数据类型 Python中的分数 Python中的算术方法 字符串(St ...

随机推荐

  1. 剑指offer 1,输入一个字符串,将字符串的空格替换成%20

    剑指offer 1,输入一个字符串,将字符串的空格替换成%20    function replaceSpace(str){      return str.replace(/\s/g,"% ...

  2. Codeforces 1105D Kilani and the Game【BFS】

    <题目链接> 题目大意: 每个玩家控制一个颜色去扩张,每个颜色的扩张有自己的速度,一个颜色跑完再跑下一种颜色.在所有颜色不能在继续扩张的时候停止游戏.询问此时各种颜色的数量. 解题分析: ...

  3. Diango之通过form表单向服务端发送数据

    通过form表单向服务端发送数据 表单元素 表单:form></form>表单用于向服务器传输数据.另外一种向服务端传输数据的方式为ajax. form属性: action:提交表单 ...

  4. javascript 作用域详解

    作用域理解:定义的变量.函数生效的范围.javascript 有全局作用域和函数作用域两种.注:es6实现let 块级作用域不是js原生的,底层同样是通过var实现的.如果想了解具体细节,请访问bab ...

  5. [洛谷P1063][NOIP2006]能量项链

    区间DP模板题 题目描述 在Mars星球上,每个Mars人都随身佩带着一串能量项链.在项链上有N颗能量珠.能量珠是一颗有头标记与尾标记的珠子,这些标记对应着某个正整数.并且,对于相邻的两颗珠子,前一颗 ...

  6. ord() expected string of length 1, but int found

    源代码是这样: s=b'^SdVkT#S ]`Y\\!^)\x8f\x80ism' key='' for i in s:     i=ord(i)-16     key+=chr(i^32) prin ...

  7. Linux 默认目录

    /etc 存放系统管理所需要的配置文件和子目录 /home 一般用户的主目录 /usr 用户使用的系统目录和应用程序等信息 /bin  存放使用者经常使用的命令 如cp  ls cat 等 /proc ...

  8. iOS12系统应用开发发送邮件

    iOS12系统应用开发发送邮件 消息分享是应用社交化和营销的重要途径.除了开发者自己搭建专有的消息分享渠道之外,还可以借助系统自带的各种途径.iOS提供了3种快速分享消息的方式,分别为发送邮件.发送短 ...

  9. UVA 221 Urban Elevations

    思路: 一些解释: ①:建筑的排序: 下面是以输入顺序为标号,在数组bd中的顺序: 排序后在数组bd中的顺序: 以后我们比较就按这个顺序 ②:x坐标的排序 x的内容是每一个建筑的左边界和右边界,我们把 ...

  10. 潭州课堂25班:Ph201805201 django 项目 第四十三课 后台 用户管理前后功能实现 (课堂笔记)

    用户的展示,编辑,删除, 把用户显示出来,用户名,员工(是,否), 超级用户(是, 否) 活跃状态,(非活跃示为删除) 在前台要显示该用户所属的用户组,在前台代码中是调用类的属性,所以在 user 的 ...