计算机中的浮点数

浮点数的一般表示方式:N=(m,e)

        在计算机中,一个以β为底(radix/base),以e为指数(exponent),有m个有效数字(significand/mantissa)的浮点数N用下面这种形式表示:

        N=m\cdot \beta ^{e}

或者写成下面的形式:

N=significand\cdot radix^{exponent}

例如,数12.345如果用以10为底,有效数字为5的浮点数来表示可以表示成下面这个样子:

         其中:

        β是底也叫进制,这个数由系统自身决定,例如上面的例子中就是以10为底的系统。但在计算机系统中则是以2为底。

        e是指数,表示底的幂次。也就是浮点数小数点的位置,比如上面的例子,我在下面把“点”给画出来了

12.345=12345.\times 10^{-3}

-3就表示只需把小数点往前移三位就能得到实际数N。

        m是有效数字部分(有些地方叫“尾数”)。 

        因此,一但系统的进制被确定以后,例如,二进制系统,β=2,那么浮点数N只需通过(m,e)这两个参数就能表示。或者说,N是m和e这两个自变量的函数。

    


浮点数的正式定义(相对正式):N=(M,e) 

        一个有限长度的,按照下列方式定义的浮点数N,被4个整数所限定:

N=M\cdot \beta ^{e-p+1}

这四个数分别是:

1,底/基数(radix or base) \beta \geq 2

2,精度(precision) p\geq 2,它表示的是小数点左边和右边有效位数字的总位数。

3,e_{min}最小指数。

4,e_{max}最大指数,一般而言e_{min}\leq 0\leq e_{max}。且,在IEEE-754标准中,e_{min}=1-e_{max}。最小指数和最大指数被称为极限指数(extremal exponents)

其中:

1,M是一个小于\beta ^{p}-1的整数,被称为整数有效数字(integral significand)。

2,指数e是一个满足e_{min}\leq e\leq e_{max}的整数。

        相对于前面的一般表示方式,浮点数N只是由β一个整数所限定,一旦β确定后,浮点数就被另外两个参数e和m确定了,也就是上面提到过的用(m,e)来表示N。

        在这里,在浮点数的正式定义中,浮点数N由4个整数β,p,emin和emax限定。一但这四个数被确定后(也是由于系统自身决定的),浮点数N就可以由M和e来表示了,在这里N变成了M和e的函数,即通过(M,e)来表示N

不同浮点数定义方式的比较
浮点数的一般表示方式浮点数的正式定义
由系统所预先设置的整数ββ,p,e_min,e_max
根据实际数自行调整的整数m,eM,e

        By the way,如果把浮点数的正式定义改写成如下的形式:

N=M\cdot \beta ^{q},q=e-p+1

        这里的\beta ^{q}被称之为量子(quantum),他代表了一个单位浮点数能表示的最小变化,量子越小,浮点数能表示的数值变化就越精细。 q被称之为量子指数(quantum exponent)


        下面通过一个例子来看看浮点数的正式定义究竟是怎么回事?同样是用浮点数的标准定义来表示12.345这个数,分两种情况来讨论。

较高的精度,较窄的指数范围:

        

        首先,把四个用于限定浮点数表示范围的数设置好β=10(还是用十进制来表示),p=10(12.345共5个数,因此,在不损失有效数字的情况下,精度至少要大于5),相当于是我在有效数字位数的基础上又多个给了5位精度,但指数e的范围给的很小e_min=-2,e_max=3。 M的范围是由p限制的,根据定义M的绝对值要小于等于\beta ^{p}-1=10^{10}-1=9999999999

表示方式1:

        如果我们希望用M=12345来表示(12345<9999999999满足要求),可以先把N表示成如下形式:

N=M\cdot \beta ^{q},q=e-p+1

12.345=12345.\times 10^{-3}

        这样一来-3=e-10+1,得到e=6,-2\leq 6\leq 3,不能满足e_{min}\leq e\leq e_{max}对指数的要求,这说明M不能用这个值。

表示方式2:

        如果用M=12345000<9999999999来表示,则:

12.345=12345000.\times 10^{-6}

        这时,-6=e-10+1,得到e=3,-2\leq 3\leq 3,能满足e_{min}\leq e\leq e_{max}对指数的要求,这也是当前指数范围内所能表示的最小的M了,即,M=12345000。

表示方式3:

        如果我们希望用M=1234500000<9999999999来表示,则:

12.345=1234500000.\times 10^{-8}

        这时,-8=e-10+1,得到e=1,-2\leq 1\leq 3,能满足e_{min}\leq e\leq e_{max}对指数的要求。这是该系统中,大M能够满足条件且指数e不超过限制的最大M了,即,M=1234500000。

        在上面的例子中,我的精度给的比较高,指数范围比较窄。能够被正常表示的M从12345000(e=3)~1234500000(e=1),在表示12.345这个数的时候没丢失精度,且有较大的余量。可见,用(M,e)来表示浮点数的方式并不是唯一的。值得一提的是,由于M必须是整数,因此,这里我们不能让M=1.2345,虽然他也小于9999999999。就本例而言,在不损失有效数字的情况下,M至少也得是12345。这些多种多样的表示方式被称为同类(cohort)


较低的精度,宽泛的指数范围:

        p=6,只多给1位精度,指数e的范围e_min=-7,e_max=8。M的范围是由p限制的,根据定义M的绝对值要小于等于\beta ^{p}-1=10^{6}-1=999999

表示方式1:

        如果我们希望用M=12345来表示(12345<999999满足要求),可以先把N表示成如下形式:

N=M\cdot \beta ^{q},q=e-p+1

12.345=12345.\times 10^{-3}

        这样一来-3=e-6+1,得到e=2,-7\leq 2\leq 8,能满足e_{min}\leq e\leq e_{max}对指数的要求。

表示方式2:

        如果我们希望用M=12345000来表示(12345000>999999不满足要求)。

表示方式3:

        如果我们希望用M=123450来表示(123450<999999满足要求),则:

12.345=123450.\times 10^{-4}

        这样一来-4=e-6+1,得到e=1,-7\leq 1\leq 8,能满足e_{min}\leq e\leq e_{max}对指数的要求。

        可见,在当前系统设定下,能够被正常表示的M只能从12345(e=2)~123450(e=1),小于上面的实验,且系统所给的较宽的指数范围也被浪费了。


比较好的精度和指数范围:

        私以为,较好的精度和指数范围应该是能够充分利用指数范围的精度。因此,对于需要被表示的数,需要摸索以找到指数范围和精度之间的trade-off。在IEEE 754(2008)中就有明确的定义,应该说这一规定是很多科学家深思熟虑后的决定,具有里程碑式的意义:

该IEEE-754标准截取自维基百科

浮点数正式定义的另一种表示: N=(s,m,e)

N=(-1)^{s}\times m\times \beta ^{e}

        1,m=\left | M \right |\cdot \beta ^{1-p},他不再像M一样一定是一个整数,而是一个仅包含一个整数位和p-1个小数位的小数。其中,0\leq m< \beta,m被称为正常有效数字(normal significand)

        2,s\in \left \{ 0,1 \right \},表示N的符号位

        3,e仍然表示指数

例子:

        还是用12.345来举例,对于前面提到的较高的精度,较窄的指数范围,β=10(还是用十进制来表示),p=10e_min=-2,e_max=3,基于m的限制0\leq m< 10,12.345能表示成下面这个样子。

        12.345=1.2345\times 10^{1}

e=1,e在给定的指数范围内。

        同样的,对于较低的精度,宽泛的指数范围,p=6e_min=-7,e_max=8,12.345也能表示成下面这个样子:

12.345=1.2345\times 10^{1}

 e=1,也在给定的指数范围内。

        这里我们注意到,m是一个大于等于0,同时小于10的数。因此,对于12.345实际上还存在另外一种表示方式:

        对于p=10e_min=-2,e_max=30\leq m< 10,12.345还能表示成下面这个样子。

        12.345=0.12345\times 10^{2}

e=2,e在给定的指数范围内。

        对于p=6e_min=-7,e_max=80\leq m< 10

12.345=0.12345\times 10^{2}

 e=2,也在给定的指数范围内。

         这说明在浮点数的正式定义中,不论是前面的(M,e)表示法,还是这里的(s,m,e)在表示数N的时候都不是唯一的。


常规数与相对少见的数normal and sub-normal numbers

        在前面的正式定义中我们已经看到了,对于同一个数而言,既存在不同的(M,e)表示,也存在不同的(s,m,e)表示。这就是表示的多样性与不唯一性,即,同类(cohort)问题。为了让有限个浮点数的表示都是唯一的(这也是人们希望看到的),人们发明/定义了下面这种表示方式,这种表示也被称作标准化表示(normalized representation)

N=(-1)^{s}\times m\times \beta ^{e}

        1,把m的范围由之前的0\leq m< \beta调整为1\leq \left | m \right |< \beta,满足这一条件的浮点数表示N被称为常规数(normal number)

        2,如果不是正规数,那么\left | m \right |< 1,且指数e必须等于e_{min},这样的N被称为相对少见的数(sub-normal number)sub-normal number常被用于表示一些非常小的数,例如所需表示的数的指数e小于e_{min}的情况。例如在一个e_{min}=-126系统中,要表示一个e=-128的数。

        如此一来N的表示就被唯一确定了!

        在基数为2的系数中,由于m被限制在1\leq \left | m \right |< 2之间,normal number有效数字的第一个位一定是1。因此,normal number的有效数字总是具有如下形式:

1.m_{1}m_{2}m_{3}...m_{p-1}

 

        而subnormal number有效数字的第一个位只能是 0,他的m被限制在\left | m \right |< 1。而subnormal number的有效数字总是具有如下形式:

0.m_{1}m_{2}m_{3}...m_{p-1}

        这两种表示方式的共有部分---数字序列“.m_{1}m_{2}m_{3}...m_{p-1}​”被称为有效数字的尾数(trailing significand),在有的地方也被称为小数部分(fraction)。此外,如果我们能够找到一种方法(这种方法通常在指数部分实现),可以告诉我们一个数是常规数normal number还是相对少见的数sub-normal number,就不需要存储其有效数字的第一位。这种不保存有效数字第一位的方法被称为隐含位约定(leading bit convention/implicit bit convention/hidden bit convention)。

        到此为止,我通过一些例子来回顾一下上面提到正规数表示和非正规表示。在一个标准化2进制系统中,精度p=24,e_{min}=-126e_{max}=127


例一,用常规数normal number的表示方式来表示\frac{1}{3}

1,符号位

        \frac{1}{3}是一个正数,所以符号位s=0。

2,化分数为小数

\frac{1}{3}=0.33333333...

3,把十进制小数转换为二进制小数

        将小数部分不断地乘以 2 依次得到:

0.3333333333...x2=0.6666666666...,取出整数部分 0,得到二进制小数部分的第一个数。

0.6666666666...x2=1.3333333333...,取出整数部分 1,得到二进制小数部分的第二个数。

0.3333333333...x2=0.6666666666...,取出整数部分 0,得到二进制小数部分的第三个数。

        依此类推,最终得到0.33333...的二进制表示(下标的10和2表示进制):

0.333333..._{(10)}=0.01010101010..._{(2)}

4,规范化表示

        基于常规数表示对m的要求,m需要符合1\leq \left | m \right |< 2。因此,上述二进制小数可以表示成1.xxxxx...的形式:

0.010101010101010..._{(2)}\Rightarrow 1.0101010101010...\times 2^{-2}_{(2)}

这样一来便得到了指数e = -2

5,在给定的精度p=24范围内,对\frac{1}{3}的二进制表示进行截取,取前24个有效数字

1.01010101010...\times 2^{-2}_{(2)}\Rightarrow 1.01010101010101010101010\times 2^{-2}_{(2)}

如果把这个截断后的二进制数返还到十进制,我们就会发现被截断后的\frac{1}{3}已经变成了:

\frac{1}{2^{2}}+\frac{1}{2^{4}}+\frac{1}{2^{6}}+...+\frac{1}{2^{22}}=0.3333333432674407958984375

最终数\frac{1}{3}在2进制中的正规数为:

N=(-1)^{s}\times m\times \beta ^{e}=(-1)^{0}\times 1.01010101010101010101010\times 2^{-2}


例二,用相对少见的数sub-normal number的方式来表示3\times 2^{-128}e_{min}=-126

      根据sub-normal number的规定:\left | m \right |< 1,且指数e必须等于e_{min}

1,符号位

        3\times 2^{-128}是一个正数,所以符号位s=0。

2,-128<-126说明这个数足够小,可以用sub-normal number来表示。令e=e_{min}=-126,得到:

3\times 2^{-128}_{(10)}=3\times 2^{-2}\times 2^{-126}_{(10)}

3,转换为二进制

3\times 2^{-2}\times 2^{-126}_{(10)}=11\times 2^{-2}\times 2^{-126}_{(2)}=0.11\times 2^{-126}_{(2)}

得到m=0.11 

4,sub-normal number的最终表示

N=(-1)^{s}\times m\times \beta ^{e}=(-1)^{0}\times 0.11\times 2^{-126}


以下是一些关于浮点数特殊值的定义:

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

\beta ^{e_{min}}

2,最小的正的相对少见的数(the smallest positive sub-normal number)

\alpha =\beta ^{e_{min}-p+1}

3,最大的有限浮点数(the largest finite floating-point number)

\Omega =(\beta -\beta ^{1-p})\cdot \beta ^{e_{max}}


(全文完) 

--- 作者,松下J27

参考文献(鸣谢): 

1,《Handbook of floating-point arithmetic》 ,second edition, Jean-Michel Muller

2,《Elementary Functions Algorithms and Implementation》,Jean-Michel Muller

3,https://en.wikipedia.org/wiki/Floating-point_arithmetic#IEEE_754:_floating_point_in_modern_computers

4,https://en.wikipedia.org/wiki/Single-precision_floating-point_format

5,https://en.wikipedia.org/wiki/Double-precision_floating-point_format

版权声明:所有的笔记,可能来自很多不同的网站和说明,在此没法一一列出,如有侵权,请告知,立即删除。欢迎大家转载,但是,如果有人引用或者COPY我的文章,必须在你的文章中注明你所使用的图片或者文字来自于我的文章,否则,侵权必究。 ----松下J27  

Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐