您的位置:首页 > 其它

Float and the form of expression of floating-point number in memory

2015-01-05 18:18 459 查看

     一个浮点数a由两个数m和e来表示:a = m × be。在任意一个这样的系统中,我们选择一个基数b(记数系统的基)和精度p(即使用多少位来存储)大部份计算机采用二進制(b=2)的表示方法。(bit)是衡量浮点数所需存储空间的单位,通常为32位或64位,分别被叫作单精度双精度.

  从数学的角度来讲,十进制的小数可以转换为二进制小数(整数部分连续除2,小数部分连续乘2),例如125.125D=1111101.001B,但问题在于计算机根本就不认识小数点“.”,更不可能认识1111101.001B。那么计算机是如何处理小数的呢?最终获得广泛应用的是IEEE 754标准中的方案,目前最新版的标准是IEEE
std 754-2008。该标准提出数字系统中的浮点数是对数学中的实数(小数)的近似,同时该标准规定表达浮点数的0、1序列被分为三部分(三个域):



     把二进制小数(补码)用二进制科学计数法表示,比如上面给出的例子1111101.001=1.111101001*2^6。

符号位sign表示数的正负(0为正,1为负),故此处填0,

     exponent表示科学计数法的指数部分,请务必注意的是,这里所填的指数并不是前面算出来的实际指数,而是等于实际指数加上一个数(指数偏移),偏移量为2^(e-1)-1,其中e是exponent的宽度(位数)。对于32位单精度浮点数,exponent宽度为8,因此偏移量为127,所以exponent的值为133,即10000101。

     fraction表示尾数,即科学计数法中的小数部分11110100100000000000000(共23位)。因此32位浮点数125.125D在计算机中就被表示为01000010111110100100000000000000

      对于32位单精度浮点数,sign是1位,exponent是8位(指数偏移量是127),fraction是23位。对于64位双精度浮点数,sign是1为,exponent是11位(指数偏移量是1023),fraction是52位。

      浮点数能表示的范围其实是有限的,它只能表示整条数轴中的三部分:某个很大的负数到某个很接近于0的负数、0、某个很接近于0的整数到某个很大的正数。此外,由数学分析的知识可知实数是“稠密”的,可以证明在任意两个不相等的实数之间总有无穷多个两两不等的实数;但浮点数不是这样,浮点数是“稀疏”的,两个浮点数之间只有有限个浮点数,并且两个“相邻”的浮点数之间的距离可能是巨大的:如

  两个“相邻”的32位单精度浮点数,它们的符号位和指数位都相同,尾数位的前22位都相同,只有最后一位相差1,那么这两个浮点数之间的差值可能是非常惊人的。例如01111110100000000000000000000001和01111110100000000000000000000000,在32位单精度情况下,它们是“相邻”的,但它们之间的差值竟高达1.014*10^31。换句话说,在32位单精度浮点数中,处于这段差值以内的数都无法表示。如果以相对误差来讨论的话,32位单精度浮点数的尾数只有23位,第24位及其后的值会被舍入,可以近似认为其相对误差为2^-23≈1.20*10^-7。这对于某些需要上亿甚至百亿次迭代的程序而言是无法接受的。而64位双精度浮点数的相对误差可以近似认为是2^-52≈
2.22*10^-16,比32位单精度浮点数的精度高出不少。可见,64位双精度浮点数不仅表示数的范围扩大了,而且它所刻画的浮点数分布更加“细密”,相对误差更小。并且,对于64位线宽度的计算机而言,处理64位双精度浮点数与处理32位双精度浮点数所需的开销相同,并不需要额外的循环移位,因此还是建议使用64位双精度浮点数。
    当然,浮点数位数越多,其相对误差也就越小,只要它的精度满足程序运行需要就可放心使用。
下面给出两个算法:
private float intBitsToFloat(int bits)

        {
           //得到符号位

            int s = ((bits >> 31) == 0) ? 1 : -1;
          //得到指数加上偏移量的值

            int e = ((bits >> 23) & 0xff);

            int m = (e == 0) ?
         

              (bits & 0x7fffff) << 1 :

              (bits & 0x7fffff) | 0x800000;

            return (float)(s * m * Math.Pow(2, e - 150));

        }

        private double longBitsToDouble(long bits)

        {

            int s = ((bits >> 63) == 0) ? 1 : -1;

            int e = (int)((bits >> 52) & 0x7ffL);

            long m = (e == 0) ?

                            (bits & 0xfffffffffffffL) << 1 :

                            (bits & 0xfffffffffffffL) | 0x10000000000000L;

            return (s * m * Math.Pow(2, e - 1075));

        }             
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐