定点数、浮点数类型运算
原文地址:https://blog.csdn.net/syb773849846/article/details/78123079
处理器在进行数值运算的时候包括整数以及小数的运算:
处理器在操作小数的时候有两种表示方式:浮点运算和定点运算!
1.1定点数(fixed-point):字面意思看,小数点位置是固定的,即约定机器中所有数据的小数点位置是不变的。在计算机中通常有两种简单的约定:将小数点的位置固定放在数据的最高位之前,或者固定在最低位数据之后,一般称前者为定点小数,后者为定点整数!
在对小数点位置作出选择之后(即定标定了Q值后),运算中的所有数均应统一为定点整数或定点小数,在运算中不再考虑小数问题。
特点:1)数据中的小数点位置固定不变
2)定点整数110. 定点小数 .101
3)小数点在符号位与有效数据位之间
定点数受字长的限制,超出范围会溢出!
举个栗子:假设以一个字节表示小数,小数点固定在5.3的位置,高5位表示整数,低3位表示小数: 11001_001 —— 11001.001
转换一下:整数部分11001= 25
小数部分001 = 1(分子部分) 分母是1000(8),所以小数部分1/8
最终的小数表示是 25+ 1/8
即存在 0/8, 1/8, 2/8, …. 7/8共八个档,表示精度为1/8
所以定点小数存在数值范围和数值精度的问题!
1.2浮点数(float-point)
在计算机系统的发展过程中,曾经提出过多种方法表达实数。典型的比如相对于浮点数的定点数(Fixed Point Number)。在这种表达方式中,小数点固定的位于实数所有数字中间的某个位置。货币的表达就可以使用这种方式,比如 99.00 或者 00.99 可以用于表达具有四位精度(Precision),小数点后有两位的货币值。定点数表达法的缺点在于其形式过于僵硬,固定的小数点位置决定了固定位数的整数部分和小数部分,不利于同时表达特别大的数或者特别小的数。即数值范围和数值精度是个矛盾的问题!最终,绝大多数现代的计算机系统采纳了所谓的浮点数表达方式!
这种表达方式利用科学计数法来表达实数,即用一个尾数(Mantissa ),一个基数(Base),一个指数(Exponent)以及一个表示正负的符号来表达实数。比如 123.45 用十进制科学计数法可以表达为 1.2345 × 102,其中 1.2345 为尾数,10 为基数,2 为指数。浮点数利用指数达到了浮动小数点的效果,从而可以灵活地表达更大范围的实数。提示: 尾数有时也称为有效数字(Significand)。尾数实际上是有效数字的非正式说法!
这样的话,同一个数值可以有多种浮点数表示方法,比如123.45可以表示成12.345x101
或者0.12345x103,由于这种多样性,有必要加以规范以达到统一表达的目的。规范的(Normalized)浮点数表达方式具有如下形式:
±d.dd...d× βe,(0 ≤ d i < β)
其中d.dd...d是尾数,β为基数,e就是指数。并且尾数中数字的个数称为精度,在本文中用 p 来表示。每个数字 d 介于 0 和基数之间,包括 0。小数点左侧的数字不为 0。
计算机内部的数值表达是基于二进制的。从上面的表达式,我们可以知道,二进制数同样可以有小数点,也同样具有类似于十进制的表达方式。只是此时 β 等于 2,而每个数字 d 只能在 0 和 1 之间取值。比如二进制数1001.101 相当于 1 × 23 + 0 × 22 + 0× 21 + 1× 20 + 1 × 2-1 + 0 × 2-2 +1 × 2-3,对应于十进制的 9.625。其规范浮点数表达为1.001101 × 23。
定点表示法运算直观,但数的表示范围较小,不同的数运算时要考虑比例因子的选取,以防止溢出。浮点表示法运算时可以不考虑溢出,但浮点运算,编程较难。要掌握定、浮点数的转换方法及浮点数规格化方法。
IEEE浮点数
IEEE二进制浮点数算术标准(IEEE 754)是20世纪80年代以来最广泛使用的浮点数运算标准,为许多CPU与浮点运算器所采用。这个标准定义了表示浮点数的格式(包括负零-0)与反常值(denormal number)),一些特殊数值(无穷(Inf)与非数值(NaN)),以及这些数值的“浮点数运算符”;它也指明了四种数值舍入规则和五种例外状况(包括例外发生的时机与处理方式)。
IEEE单精度格式具有24位有效数字(1个符号位,23位尾数),8位的指数部分,总共占用32 位。IEEE双精度格式具有53位有效数字精度(1个符号位,52位尾数),11位的指数部分,并总共占用64位。
说明:基本浮点格式是固定格式,相对应的十进制有效数字分别为7位和17位。基本浮点格式对应的C/C++类型为float和double。
b) 浮点到定点的四种舍入(截断)方向:
向最接近的可表示的值;当有两个最接近的可表示的值时首选"偶数"值;向负无穷大(向下);向正无穷大(向上)以及向0(截断)。
说明:舍入模式也是比较容易引起误解的地方之一。IEEE 754标准根本不支持四舍五入模式,它的默认模式是最近舍入(Round toNearest),它与四舍五入只有一点不同,对.5的舍入上,采用取偶数的方式。如:
最近舍入模式:Round(0.5) = 0; Round(1.5) = 2; Round(2.5) = 2;
四舍五入模式:Round(0.5) = 1; Round(1.5) = 2; Round(2.5) = 3;
向0(截断)舍入:C/C++的类型转换。(int) 1.324 = 1,(int) -1.324 = -1;
向负无穷大(向下)舍入:C/C++函数floor()。例如:floor(1.324) = 1,floor(-1.324)= -2。
向正无穷大(向上)舍入:C/C++函数ceil()。ceil(1.324) = 2。Ceil(-1.324)= -1;
后两种舍入方法据说是为了数值计算中的区间算法,但很少被应用
2、定点数的运算:
2.1 数的定标
在许多情况下,数学运算过程中的数不一定都是整数,而且定点DSP和不带FPU的处理器是无能为力的。那么是不是说定点DSP和不带FPU的处理器就不能处理各种小数呢?当然不是。这其中的关键就是由程序员来确定一个数的小数点处于数据中的哪一位。这就是数的定标(由于很多时候,我们都是直接用C来实现浮点运算,具体的底层转化我们并没有去关心,所以也就很少有人知道数的定标)。
通过设定小数点在数据中的不同位置,就可以表示不同大小和不同精度的小数了。数的定标有Q表示法和S表示法两种。下表列出了一个16位数的16种Q表示、S表示及它们所能表示的十进制数值范围。
Q表示 S表示 十进制数表示范围
Q15 S0.15 -1≤x≤0.9999695
Q14 S1.14 -2≤x≤1.9999390
Q13 S2.13 -4≤x≤3.9998779
Q12 S3.12 -8≤x≤7.9997559
Q11 S4.11 -16≤x≤15.9995117
Q10 S5.10 -32≤x≤31.9990234
Q9 S6.9 -64≤x≤63.9980469
Q8 S7.8 -128≤x≤127.9960938
Q7 S8.7 -256≤x≤255.9921875
Q6 S9.6 -512≤x≤511.9804375
Q5 S10.5 -1024≤x≤1023.96875
Q4 S11.4 -2048≤x≤2047.9375
Q3 S12.3 -4096≤x≤4095.875
Q2 S13.2 -8192≤x≤8191.75
Q1 S14.1 -16384≤x≤16383.5
Q0 S15.0 -32768≤x≤32767
从上表可以看出,同样一个16位数,若小数点设定的位置不同,它所表示的数也就不同。例如,
16进制数2000H=8192,用Q0表示
16进制数2000H=0.25,用Q15表示
还可以看出,不同的Q所表示的数不仅范围不同,而且精度也不相同。Q越大,数值范围越小,但精度越高;相反,Q越小,数值范围越大,但精度就越低。例如,Q0的数值范围是-32768到+32767,其精度为1,而Q15的数值范围为-1到0.9999695,精度为1/32768=0.00003051。因此,对定点数而言,数值范围与精度是一对矛盾,一个变量要想能够表示比较大的数值范围,必须以牺牲精度为代价;而想精度提高,则数的表示范围就相应地减小。在实际的定点算法中,为了达到最佳的性能,必须充分考虑到这一点。
浮点数与定点数的转换关系可表示为:
浮点数(x)转换为定点数(xq):xq=(int)x* 2Q
定点数(xq)转换为浮点数(x):x=(float)xq*2-Q
例如,浮点数x=0.5,定标Q=15,则定点数xq=L0.5*32768J=16384,式中LJ表示下取整。反之,一个用Q=15表示的定点数16384,其浮点数为16384 *2^-15=16384/32768=0.5。浮点数转换为定点数时,为了降低截尾误差,在取整前可以先加上0.5。
参考博文:
1、 http://blog.csdn.net/iamshaofa/article/details/49805045
2、 http://bbs.elecfans.com/jishu_486119_1_1.html
3、 http://houh-1984.blog.163.com/blog/static/311278342011101251758295/