浮点数、定点数

什么是定点数

通俗的解释

​ 定点数指小数点在数中的位置是固定不变的,通常有定点整数和定点小数。在对小数点位置作出选择之后,运算中的所有数均应统一为定点整数或定点小数,在运算中不再考虑小数问题。

​ 以人民币为例,我们日常经常说到的如123.45¥,789.34¥等等,默认的情况下,小数点后面有两位小数,即角,分。如果小数点在最高有效位的前面,则这样的数称为纯小数的定点数,如0.12345,0.78934等。如果小数点在最低有效位的后面,则这样的数称为纯整数的定点数,如12345,78934等。

专业的说法

​ 所谓定点格式,即约定机器中所有数据的小数点位置是固定不变的。通常将定点数据表示成纯小数或纯整数,为了将数表示成纯小数,通常把小数点固定在数值部分的最高位之前;而为了将数表示成纯整数,则把小数点固定在数值部分的最后面,如下图所示:

什么是浮点数

通俗的解释

​ 浮点数:一般说来,小数点不固定的数。比较容易的理解方式是,考虑以下我们日常见到的科学记数法,拿我们上面的数字举例,如123.45,可以写成以下几种形式

如:

12.345x10^1^

1.2345 x10^2^

0.12345 x10^3^

……

为了表示一个数,小数点的位置可以变化,即小数点不固定。

专业的说法

​ 定点数表示法的缺点在于其形式过于僵硬,固定的小数点位置决定了固定位数的整数部分和小数部分,不利于同时表达特别大或特别小的数,最终,绝大多数现代的计算机系统采纳了浮点数表达方式,这种表达方式利用科学计数法来表达实数,即用一个尾数(Mantissa,尾数有时也称为有效数字,它实际上是有效数字的非正式说法),一个基数(Base),一个指数(Exponent)以及一个表示正负的符号来表达实数,比如123.45用十进制科学计数法可以表示为1.2345x10^2^,其中1.2345为尾数,10为基数,2为指数。浮点数利用指数达到了浮动小数点的效果,从而可以灵活地表达更大范围的实数。

定点数与浮点数的对比

​ 定点表示法运算直观,但数的表示范围较小,不同的数运算时要考虑比例因子的选取,以防止溢出。浮点表示法运算时可以不考虑溢出,但浮点运算,编程较难。要掌握定、浮点数的转换方法及浮点数规格化方法。

表示的精度与范围不同

​ 例如,我们用4个十进制数来表达一个数字。对于定点数(这里以定点整数为例),我们表示区间[0000,9999]中的任何一个数字,但是如果我们要想表示类似1234.3的数值就无能为力了,因为此时的表示精度为1/10^0^=1;如果采用浮点数来表示(以归整的科学记数法,即小数点前有一位有效位,为例),则可以表示[0.000,9.999]之间的任何一个数字,表示的精度为1/10^3^=0.001,精度比上一种方式提高了很多,但是表示的范围却小了很多。

​ 也就是说,一般的,定点数表示的精度较低,但表示的数值范围较大;而浮点数恰恰相反。

计算机中运算的效率不同

​ 一般说来,定点数的运算在计算机中实现起来比较简单,效率较高;而浮点数的运算在计算机中实现起来比较复杂,效率相对较低。

硬件依赖性

​ 一般说来,只要有硬件提供运算的部件,就会提供定点数运算的支持(不知道说的确切否,没有听说过不支持定点数运算的硬件),但不一定支持浮点数运算,如有的很多嵌入式开发板就不提供浮点运算的支持。

浮点数的存储格式

IEEE 浮点格式规范

​ 浮点数的小数点是不固定的,如果每个人都按照自己的爱好存储在电脑里,那不就乱套了吗?那么怎么在计算机中存储这种类型的数字呢?象这类古老的问题前人早都为我们做好了相应的规范,无规矩不成方圆吗。我们平时所说的浮点数的存储规范,就是由IEEE指定的,具体的规范文件是:IEEE Standard 754 for Binary Floating-Point Arithmetic。大家可以很容易的从网络上下载到这篇文档。

单精度浮点

在c语言中,单精度(float)数据类型为32bits,具体的如下图所示:

整个32bits分三部分,即

  Sign:符号位,1 bit,0为正,1为负;

  Exponent(bias):指数部分,8 bits,存储格式为移码存储(后面还会说明),偏移量为127;

  Mantissa(fraction):尾数部分。

双精度浮点

  对应的双精度(double)类型的格式为:

​ 同样,64位也被分为了三部分,对照单精度,不用我说就可以理解各个部分的含义了吧?

  是不是有点迷糊了,不要怕,理论这个东西最能忽悠人了,看起来很高深,其实也就是个屁大的事,举个例子就很容易明白了。

举例说明,如3.24x10^3^,则对应的部分为,Sign为0,3为指数部分(注意计算机里面存储的不是3,这里仅仅为了说明),3.24为尾数。我们知道,计算机“笨”的要死,只认识0和1,那么到底一个浮点数值在计算机存储介质中是如何存储的呢?

例如,我们要想偷窥浮点类型的值4.25在计算机硬盘中存储的庐山真面目,请跟我来:首先把4.25转换成二进制的表达方式,即100.01,在详细点,变成1.0001x2^2^,好了,对号入座把。

Sign=0;

Exponent(bias)=2+127=129 (偏移量为127,就是直接加上个127了);

Mantissa=1.0001-1.0=0001(规格化后,小数点前总是整数1,全世界人都知道前面是1不是0,所以省略不写了,即尾数部分不包括整数部分;当别人问你,为什么23 bit的尾数部分可以表示24位的精度,知道怎么回答了吧。 靠,什么,没有看懂,再仔细读两便就知道了)。

​ 对照上面的图示,相信你已经看明白了吧?相信你的智商。为了加深认识,再来一个。如果给定你一个二进制数字串

01000000100010000000000000000000

并告诉你这是一个float类型的值,让你说出它是老几,知道怎么算了吧?如果不知道,看下面的图,我就不废话解释了。

浮点定点转换

Q格式定标法

​ 通过假定小数点位于哪一位(Q)的右侧,从而确定小数的精度,以下为32位数Q定标表格。

Q表示 十进制浮点数表示范围 精度
Q=31 -1≤x≤0.999 999 999 2^(-31)
Q=30 -2≤x≤1.999 999 999 2^(-30)
Q=29 -4≤x≤3.999 999 998 2^(-29)
Q=28 -8≤x≤7.999 999 996 2^(-28)
Q=27 -16≤x≤15.999 999 993 2^(-27)
Q=26 -32≤x≤31.999 999 985 2^(-26)
Q=25 -64≤x≤63.999 999 970 2^(-25)
Q=24 -128≤x≤127.999 999 940 2^(-24)
Q=23 -256≤x≤255.999 999 981 2^(-23)
Q=22 -512≤x≤511.999 999 762 2^(-22)
Q=21 -1024≤x≤1023.999 999 523 2^(-21)
Q=20 -2048≤x≤2047.999 999 046 2^(-20)
Q=19 -4096≤x≤4095.999 998 093 2^(-19)
Q=18 -8192≤x≤8191.999 996 185 2^(-18)
Q=17 -16384≤x≤16363.999 992 371 2^(-17)
Q=16 -32768≤x≤32767.999 984 741 2^(-16)
Q=15 -65536≤x≤65535.999 969 482 2^(-15)
Q=14 -131072≤x≤131071.999 938 965 2^(-14)
Q=13 -262144≤x≤262143.999 877 930 2^(-13)
Q=12 -5244288≤x≤524287.999 755 859 2^(-12)
Q=11 -1048576≤x≤1048575.999 511 719 2^(-11)
Q=10 -2097152≤x≤2097151.999 511 719 2^(-10)
Q=9 -4194304≤x≤4194302.998 046 875 2^(-9)
Q=8 -8388608≤x≤8388607.996 093 750 2^(-8)
Q=7 -16777216≤x≤16777215.992 187 500 2^(-7)
Q=6 -33554432≤x≤33554431.984 375 000 2^(-6)
Q=5 -67108864≤x≤67108863.968 750 000 2^(-5)
Q=4 -134217728≤x≤134217727.937 500 000 2^(-4)
Q=3 -268435456≤x≤268435455.875 000 000 2^(-3)
Q=2 -536870912≤x≤536870911.750 000 000 2^(-2)
Q=1 -1073741824≤x≤1073741823.500 000 000 2^(-1)
Q=0 -2147483648≤x≤2147483647 2^0

转换关系

浮点数(X)转换为定点数(Xq):Xq=(int)X* 2^Q

定点数(Xq)转换为浮点数(X):X=(float)Xq*2^(-Q)

Example:

将浮点数X = 0.5转换为32位Q定标的定点数:

  • (1)由于-1≤X≤0.999 999 999,按照上述表格所以我们取Q = 31,

    即定点数:Xq=(int)X 2^Q = (int)(0.5 2^31) = 1073741842;

    反之知道定点数Xq = 1073741842 反推其浮点数如下

    则X=(float)Xq2^(-Q) = (float)10737418422^(-31) = 0.5;

    ​ 按照上述如果我们取Q = 31,如果我们要计算浮点的0.50.5,则相当于计算定点的1073741842 1073741842 这个数实在是太大了,只能用long long型装下,而非一个字(int)可以装下。通过观察0.5这个数我们只需要保证表格中的Q值对应的精度比0.5更小即可,如此我们重新选择Q:

  • (2)由于-536870912≤x≤536870911.750 000 000,按照上述表格我们取Q = 2, 即定点数:Xq=(int)X 2^Q = (int)(0.5 2^2) = 2; 反之知道定点数Xq = 2 反推其浮点数如下 则X=(float)Xq2^(-2) = (float)22^(-2) = 0.5; 按照上述如果我们取Q = 2,如果我们要计算浮点的0.50.5,则相当于计算定点的2 2,一个char就可以装下了。

文章作者: Sirius65535
文章链接: http://sirius.ink/2018/03/21/浮点数、定点数/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Sirius' Notes