Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

浮点数详解(IEEE 754标准) #27

Open
fang0jun opened this issue Oct 21, 2020 · 0 comments
Open

浮点数详解(IEEE 754标准) #27

fang0jun opened this issue Oct 21, 2020 · 0 comments
Labels

Comments

@fang0jun
Copy link
Owner

在这里插入图片描述


==【浮点数有关】==
在计算机发展过程中,曾经提出过许多种实数的表达方法,比较典型的有浮点数,定点数两种

【定点数简介】
|| 在定点数表达法中,其小数点固定地位于实数所有数字中间的某个位置。例如,货币的表达就可以采用这种表达方式,如 55.00 或者 00.55 可以用于表达具有 4 位精度,小数点后有两位的货币值。由于小数点位置固定,所以可以直接用 4 位数值来表达相应的数值。

|| 但我们不难发现,定点数表达法的缺点就在于其形式过于僵硬,固定的小数点位置决定了固定位数的整数部分和小数部分,不利于同时表达特别大的数或者特别小的数。因此,最终绝大多数现代的计算机系统都采纳了所谓的浮点数表达法。

【浮点数简介】
|| 浮点数表达法采用了科学计数法来表达实数,即用一个有效数字。一个基数(Base)、一个指数(Exponent)以及一个表示正负的符号来表达实数。比如,666.66 用十进制科学计数法可以表达为 6.6666×102(其中,6.6666 为有效数字,10 为基数,2 为指数)。浮点数利用指数达到了浮动小数点的效果,从而可以灵活地表达更大范围的实数。

|| 当然,对实数的浮点表示仅作如上的规定是不够的,因为同一实数的浮点表示还不是唯一的。例如,上面例子中的 666.66 可以表达为 0.66666×103、6.6666×102 或者 66.666×101 三种方式。因为这种表达的多样性,因此有必要对其加以规范化以达到统一表达的目标。规范的浮点数表达方式具有如下形式:
在这里插入图片描述(其中,d.dd…d 为有效数字,β 为基数,e 为指数)

|| 有效数字中数字的个数称为精度,我们可以用 p 来表示,即可称为 p 位有效数字精度。

||十进制的基数 β 等于 10,每个数字 d 只能在 0 和 9 之间取值 , 二进制的 β 等于 2,而每个数字 d 只能在 0 和 1 之间取值。他们之间的转换关系式(在第二步进行了十进制的运算)
在这里插入图片描述

|| 由上面的等式,我们可以得出:
1,向左移动二进制小数点一位相当于这个数除以 2,而向右移动二进制小数点一位相当于这个数乘2。如 101.11=3/4,而 10.111=7/8。
2,一个十进制小数要能用浮点数精确地表示,最后一位必为5(当然这是必要条件,并非充分条件)
可以使用程序证明:

#include <stdio.h>
int main(void)
{
    float f1=34.6;
    float f2=34.5;
    float f3=34.0;
    printf("34.6-34.0=%f\n",f1-f3);
    printf("34.5-34.0=%f\n",f2-f3);
    return 0;
}

|| 误差原理:因为计算机将二进制转换为十进制的浮点数时,若十进制浮点数尾数非5/0,会因为二进制数无法精确转化为该数而保存四舍五入的结果,故造成了误差,如下图:

在这里插入图片描述

因此,建议不要将浮点数用于精确计算!!!
且建议不要将浮点数直接用 == 或 != 进行比较,尽量转换为><号

#include <stdio.h>
int main(void)
{
    float f1=34.7;
   	if(f1 - 34.7 < 0.001) 
    	printf("Right!");
	
	if(f1 == 34.7)
		printf("Right!");
	
    return 0;
}

==【IEEE浮点数表示法】==

|| 本质:IEEE 浮点数标准是从逻辑上用三元组{S,E,M}来表示一个浮点数 V 的,即 V=(-1)S×M×2E
在这里插入图片描述

  • 符号位 s(Sign)决定数是正数(s=0)还是负数(s=1),而对于数值 0 的符号位解释则作为特殊情况处理。

  • 有效数字位 M(Significand)是二进制小数,它的取值范围为 12-ε,或者为
    0
    1-ε。它也被称为尾数位(Mantissa)、系数位(Coefficient),甚至还被称作“小数”。

  • 指数位E(Exponent)是 2 的幂(可能是负数),它的作用是对浮点数加权。

||(分析思路:位数 = =》 有效范围 = =》实际范围 )

【32位单精度浮点数详解】

Float
S--------E-------M
1位-----8位-----23位

M位:代表其精度,有效数字的个数有 2^ (23+1) = 16777216个,即二进制数的范围为(0,16777216) 化为十进制:10^ 7 < 16777216 < 10^8,所以说单精度浮点数的有效位数是7位

E位:代表其指数位:有效数字个数有 2^ 8 = 256个,即指数范围为(0,255)除去第一个和最后一个数字作为特殊值,有效指数的范围为(1,254),设置一个偏差值(2k-1-1)= -127 使之可以表示负指数,故实际指数范围(-126,127),可以代表127个正指数和126个负指数加1个零指数。

【64位双精度浮点数详解】

Double
S--------E-------M
1位-----11位----52位

M位:代表其精度,有效数字个数有*2^ (52+1) = 9007199254740992,又10^ 16 < 9007199254740992 < 10^17,所以双精度的有效位数是16位
E位:代表其指数位:有效数字个数有 2^ 11 = 2048个,即指数范围为(0,2047)除去第一个和最后一个数字作为特殊值,有效指数的范围为(1,2046),设置一个偏差值(2k-1-1)= 1023 使之可以表示负指数,故实际指数范围(-1022,1023),可以代表1023个正指数和11022个负指数加1个零指数。

|| 浮点异常值:NAN,QNAN,SNAN
这里所要说的浮点异常值就是这种IEEE浮点表示产生的几种特殊值,IEEE规定根据指数和尾数的不同分别可表示如下几种特殊值:

  1. 零值:按上述的浮点表述形式如果指数部分全部为0,并且尾数全部为0,则表示为浮点0.0,并且规定-0 = +0

  2. 非规格化值:如果指数全部为0,尾数非0,则表示非规格化的值,16进制看到的就是[80xxxxxx]h或者[00xxxxxx]h

  3. 无穷值:如果指数全部为1,尾数全部为0,则根据符号位分别表示正无穷大和负无穷大,16进制看到的就是[FF800000]h或者[7F800000]h

  4. NAN:如果指数全部为1,尾数非0,则表示这个值不是一个真正的值(Not A Number)。NAN又分成两类:QNAN(Quiet NAN)和SNAN(Singaling NAN)。
    QNAN与SNAN的不同之处在于,QNAN的尾数部分最高位定义为1,SNAN最高位定义为0;
    QNAN一般表示未定义的算术运算结果(技术NaN),最常见的莫过于除0运算;SNAN一般被用于标记未初始化的值 (信号NaN),以此来捕获异常。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

1 participant