浮点数在内存中的存储方式

上传人:ji****72 文档编号:37972630 上传时间:2018-04-25 格式:DOC 页数:11 大小:63KB
返回 下载 相关 举报
浮点数在内存中的存储方式_第1页
第1页 / 共11页
浮点数在内存中的存储方式_第2页
第2页 / 共11页
浮点数在内存中的存储方式_第3页
第3页 / 共11页
浮点数在内存中的存储方式_第4页
第4页 / 共11页
浮点数在内存中的存储方式_第5页
第5页 / 共11页
点击查看更多>>
资源描述

《浮点数在内存中的存储方式》由会员分享,可在线阅读,更多相关《浮点数在内存中的存储方式(11页珍藏版)》请在金锄头文库上搜索。

1、浮点数在内存中的存储方式 任何数据在内存中都是以二进制的形式存储的,例如一个 short 型数据 1156,其二进制表示形式为 00000100 10000100。则在 Intel CPU 架构的系统中,存放方式为 10000100(低地址单元) 00000100(高地址单元),因为 Intel CPU 的架构是小端模式。但是对于浮点数在内存是如何存储的?目前所有的 C/C+编译器都是采用 IEEE 所制定的标准浮点格式,即二进制科学表示法。在二进制科学表示法中,S=M*2N 主要由三部分构成:符号位+阶码(N)+尾数(M)。对于 float 型数据,其二进制有 32 位,其中符号位 1 位,

2、阶码 8 位,尾数 23 位;对于 double 型数据,其二进制为 64 位,符号位 1 位,阶码 11 位,尾数 52 位。31 30-23 22-0float 符号位 阶码 尾数63 62-52 51-0double 符号位 阶码 尾数符号位:0 表示正,1 表示负阶码:这里阶码采用移码表示,对于 float 型数据其规定偏置量为 127,阶码有正有负,对于 8 位二进制,则其表示范围为-128-127,double 型规定为 1023,其表示范围为-1024-1023。比如对于 float 型数据,若阶码的真实值为 2,则加上 127 后为 129,其阶码表示形式为 10000010尾

3、数:有效数字位,即部分二进制位(小数点后面的二进制位),因为规定 M 的整数部分恒为 1,所以这个 1 就不进行存储了。Comment dp1: 2 125 余 1 下面举例说明:float 型数据 125.5 转换为标准浮点格式125 二进制表示形式为 1111101,小数部分表示为二进制为 1,则 125.5 二进制表示为1111101.1,由于规定尾数的整数部分恒为 1,则表示为 1.1111011*26,阶码为6,加上 127 为 133,则表示为 10000101,而对于尾数将整数部分 1 去掉,为1111011,在其后面补 0 使其位数达到 23 位,则为 111101100000

4、00000000000则其二进制表示形式为0 10000101 11110110000000000000000,则在内存中存放方式为:00000000 低地址000000001111101101000010 高地址而反过来若要根据二进制形式求算浮点数如 0 10000101 11110110000000000000000由于符号为为 0,则为正数。阶码为 133-127=6,尾数为11110110000000000000000,则其真实尾数为 1.1111011。所以其大小为1.1111011*26,将小数点右移 6 位,得到 1111101.1,而 1111101 的十进制为125,0.1

5、的十进制为 1*2(-1)=0.5,所以其大小为 125.5。同理若将 float 型数据 0.5 转换为二进制形式0.5 的二进制形式为 0.1,由于规定正数部分必须为 1,将小数点右移 1 位,则为1.0*2(-1),其阶码为-1+127=126,表示为 01111110,而尾数 1.0 去掉整数部分为 0,补齐 0 到 23 位 00000000000000000000000,则其二进制表示形式为0 01111110 00000000000000000000000由上分析可知 float 型数据最大表示范围为1.11111111111111111111111*2127=3.4*1038对

6、于 double 型数据情况类似,只不过其阶码为 11 位,偏置量为 1023,尾数为 52 位。定点数与浮点数区别定点数与浮点数区别最近做 HDR 时,经常要用 NV 提供的 16 位纹理,它的说明书 16 位能达到 24 位的精度,就很奇怪?一直搞不懂浮点数的精度怎么算的? 今天认真看了一下 IEEE float point 的标准,终于明白是什么了 1. 什么是浮点数 在计算机系统的发展过程中,曾经提出过多种方法表达实数。典型的比如相对 于浮点数的定点数(Fixed Point Number)。在这种表达方式中,小数点 固定的位于实数所有数字中间的某个位置。货币的表达就可以使用这种方式,

7、 比如 99.00 或者 00.99 可以用于表达具有四位精度( Precision),小数 点后有两位的货币值。由于小数点位置固定,所以可以直接用四位数值来表达 相应的数值。SQL 中的 NUMBER 数据类型就是利用定点数来定义的。还 有一种提议的表达方式为有理数表达方式,即用两个整数的比值来表达实数。定点数表达法的缺点在于其形式过于僵硬,固定的小数点位置决定了固定位数 的整数部分和小数部分,不利于同时表达特别大的数或者特别小的数。最终, 绝大多数现代的计算机系统采纳了所谓的浮点数表达方式。这种表达方式利用 科学计数法来表达实数,即用一个尾数( Mantissa ),一个基数(Base),

8、 一个指数(Exponent)以及一个表示正负的符号来表达实数。比如 123.45 用十进制科学计数法可以表达为 1.2345 102 ,其中 1.2345 为尾数,10 为基数,2 为指数。浮点数利用指数达到了浮动小数点的效果, 从而可以灵活地表达更大范围的实数。提示: 尾数有时也称为有效数字( Significand)。尾数实际上是有效数字的 非正式说法。同样的数值可以有多种浮点数表达方式,比如上面例子中的 123.45 可以 表达为 12.345 101,0.12345 103 或者 1.2345 102。因为这 种多样性,有必要对其加以规范化以达到统一表达的目标。规范的 (Normal

9、ized)浮点数表达方式具有如下形式:d.dd.d e , (0 d i 和 = 在任一操作数为 NaN 时均返回 false。等于 操作符 = 在任一操作数为 NaN 时均返回 false,即使是两个具有相同位 模式的 NaN 也一样。而操作符 != 则当任一操作数为 NaN 时返回 true。这个规则的一个有趣的结果是 x!=x 当 x 为 NaN 时竟然为真。可以产生 NaN 的操作如下所示:此外,任何有 NaN 作为操作数的操作也将产生 NaN。用特殊的 NaN 来 表达上述运算错误的意义在于避免了因这些错误而导致运算的不必要的终止。 比如,如果一个被循环调用的浮点运算方法,可能由于输

10、入的参数问题而导致 发生这些错误,NaN 使得 即使某次循环发生了这样的错误,也可以简单地 继续执行循环以进行那些没有错误的运算。你可能想到,既然 Java 有异常 处理机制,也许可以通过捕获并忽略异常达到相同的效果。但是,要知道, IEEE 标准不是仅仅为 Java 而制定的,各种语言处理异常的机制不尽相同, 这将使得代码的迁移变得更加困难。何况,不是所有语言都有类似的异常或者 信号(Signal)处理机制。注意: Java 中,不同于浮点数的处理,整数的 0 除以 0 将抛出 java.lang.ArithmeticException 异常。4.2. 无穷 和 NaN 一样,特殊值无穷(I

11、nfinity)的指数部分同样为 emax + 1 = 128,不过无穷的尾数域必须为零。无穷用于表达计算中产生的上溢 (Overflow)问题。比如两个极大的数相乘时,尽管两个操作数本身可以用 保存为浮点数,但其结果可能大到无法保存为浮点数,而必须进行舍入。根据 IEEE 标准,此时不是将结果舍入为可以保存的最大的浮点数(因为这个数可 能离实际的结果相差太远而毫无意义),而是将其舍入为无穷。对于负数结果 也是如此,只不过此时舍入为负无穷,也就是说符号域为 1 的无穷。有了 NaN 的经验我们不难理解,特殊值无穷使得计算中发生的上溢错误不必以终 止运算为结果。无穷和除 NaN 以外的其它浮点数

12、一样是有序的,从小到大依次为负无穷, 负的有穷非零值,正负零(随后介绍),正的有穷非零值以及正无穷。除 NaN 以外的任何非零值除以零,结果都将是无穷,而符号则由作为除数的零 的符号决定。回顾我们对 NaN 的介绍,当零除以零时得到的结果不是无穷而是 NaN 。 原因不难理解,当除数和被除数都逼近于零时,其商可能为任何值,所以 IEEE 标准决定此时用 NaN 作为商比较合适。4.3. 有符号的零 因为 IEEE 标准的浮点数格式中,小数点左侧的 1 是隐藏的,而零显然需 要尾数必须是零。所以,零也就无法直接用这种格式表达而只能特殊处理。实际上,零保存为尾数域为全为 0,指数域为 emin -

13、 1 = -127,也就是 说指数域也全为 0。考虑到符号域的作用,所以存在着两个零,即 +0 和 -0。不同于正负无穷之间是有序的, IEEE 标准规定正负零是相等的。零有正负之分,的确非常容易让人困惑。这一点是基于数值分析的多种考虑, 经利弊权衡后形成的结果。有符号的零可以避免运算中,特别是涉及无穷的运 算中,符号信息的丢失。举例而言,如果零无符号,则等式 1/(1/x) = x 当 x = 时不再成立。原因是如果零无符号, 1 和正负无穷的比值为同 一个零,然后 1 与 0 的比值为正无穷,符号没有了。解决这个问题,除非 无穷也没有符号。但是无穷的符号表达了上溢发生在数轴的哪一侧,这个信

14、息 显然是不能不要的。零有符号也造成了其它问题,比如当 x=y 时,等式1/x = 1/y 在 x 和 y 分别为 +0 和 -0 时,两端分别为正无穷和负无穷 而不再成立。当然,解决这个问题的另一个思路是和无穷一样,规定零也是有 序的。但是,如果零是有序的,则即使 if (x=0) 这样简单的判断也由于 x 可能是 0 而变得不确定了。两害取其轻者,零还是无序的好。4.4. 非规范化数 我们来考察浮点数的一个特殊情况。选择两个绝对值极小的浮点数,以单精度 的二进制浮点数为例,比如 1.001 2-125 和 1.0001 2-125 这两个 数(分别对应于十进制的 2.6448623 10-

15、38 和 2.4979255 10- 38)。显然,他们都是普通的浮点数(指数为 -125,大于允许的最小值 - 126;尾数更没问题),按照 IEEE 754 可以分别保存为 00000001000100000000000000000000(0x1100000)和 00000001000010000000000000000000(0x1080000)。现在我们看看这两个浮点数的差值。不难得出,该差值为 0.0001 2- 125,表达为规范浮点数则为 1.0 2-129。问题在于其指数大于允许的最 小指数值,所以无法保存为规范浮点数。最终,只能近似为零( Flush to Zero)。这中特

16、殊情况意味着下面本来十分可靠的代码也可能出现问题:if (x != y) z = 1 / (x -y); 正如我们精心选择的两个浮点数展现的问题一样,即使 x 不等于 y,x 和 y 的差值仍然可能绝对值过小,而近似为零,导致除以 0 的情况发生。为了解决此类问题,IEEE 标准中引入了非规范(Denormalized)浮点数。 规定当浮点数的指数为允许的最小指数值,即 emin 时,尾数不必是规范化 的。比如上面例子中的差值可以表达为非规范的浮点数 0.001 2-126, 其中指数 -126 等于 emin。注意,这里规定的是“不必“,这也就意味着“ 可以“。当浮点数实际的指数为 emin,且指数域也为 emin 时,该浮点数 仍是规范的,也就是说,保存时隐含着一个

展开阅读全文
相关资源
相关搜索

当前位置:首页 > 行业资料 > 其它行业文档

电脑版 |金锄头文库版权所有
经营许可证:蜀ICP备13022795号 | 川公网安备 51140202000112号