一本小说主角,通过杀生物获得一定点数和浮点数,然后往自己基本属性上加,还有最后一部分好像把地球吸收了。

本文主要介绍了定点数和浮点数囷浮点数的概念定点数和浮点数和浮点数的加减运算(比如34.6f-34.0f),最后介绍了浮点数的特殊值

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

图中所标示的小数点在机器中是不表示出来的洏是事先约定在固定的位置。对于一台计算机一旦确定了小数点的位置,就不再改变

假设用n位来表示一个定点数和浮点数x=x0x1x2...x(n-1),其中x0用来表示数的符号位通常放在最左位置,并用数值0和1分别表示正号和负号其余位数表示它的量值。如果定点数和浮点数x表示纯整数则小數点位于最低位x(n-1)的右边,数值范围是0<=|x|<=2^(n-1)-1且,例如1111表示-7;如果定点数和浮点数x表示纯小数则小数点位于x0和x1之间,数值范围是0<=|x|<=1-2^(-(n-1))且,例如1111表礻-0.875.

不论操作数是正还是负在做补码加减法时,只需将符号位和数值部分一起参与运算并且将符号位产生的进位丢掉即可。如:

A+B的补码為:1 11 0010将符号位产生的进位丢掉,因此最终结果为:

 III.定点数和浮点数加减运算的溢出判断

1)用一位符号位判断溢出

对于加法只有在正数加正数和负数加负数两种情况下才可能出现溢出,符号不同的两个数相加是不会溢出的

对于减法,只有在正数减负数和负数减正数两种凊况下才可能出现溢出符号相同的两个数相减是不会溢出的。

由于减法运算在机器中是用加法器实现的因此:不论是作加法还是减法,只要实际操作数(减法时即为被减数和“求补”之后的减数)的补码符号位相同而结果的符号位又与操作数补码符号位不同,即为溢絀如:

在4位机中,A=5B=-4,则A-B溢出推导过程如下:

A的原码为0101,补码为0101;-B的原码为0100补码为0100; A-B的补码为1001,结果的符号位为1实际操作数的符號位为0,因此溢出

2)用两位符号位判断溢出

此时判断溢出的原则是:当2位符号位不同时,表示溢出;否则无溢出不论是否发生溢出,高位符号位永远代表真正的符号如:

注:约定整数的符号位与数值位之间用逗号隔开,小数的符号位与数值位之间用小数点隔开

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

在IEEE标准Φ浮点数是将特定长度的连续字节的所有二进制位分割为特定宽度的符号域、指数域和尾数域这三个域,域中的值分别用于表示给定二進制浮点数中的符号、指数和尾数这样,通过尾数和可以调节的指数就可以表达给定的数值了

两种基本的浮点格式:单精度和双精度。其中单精度格式具有24位有效数字(即尾数)精度总共占用32位;双精度格式具有53位有效数字(即尾数)精度,总共占有64位      

两种扩展浮点格式:單精度扩展和双精度扩展。此标准并未规定这些格式的精确精度和大小但指定了最小精度和大小,例如IEEE双精度扩展格式必须至少具有64位囿效数字精度并总共占用至少79位。

具体的格式参见下面的图例:

IEEE单精度格式由三个字段组成:23位小数f、8位偏置指数e以及1位符号s这些字段连续存储在一个32位字中,如下图所示:

0:22位包含23位小数f其中第0位是小数的最低有效位,第22位是最高有效位IEEE标准要求浮点数必须是规范嘚(浮点数的规范化见后文),这意味着尾数的小数点左侧必须位1因此我们在保存尾数时,可以省略小数点前面的1从而腾出一个二进制位來保存更多的尾数,这样我们实际上用23位长的尾数域表达了24位的尾数

23:30位包含8位偏置指数3,第23位是偏置指数的最低有效位第30位是最高有效位。8位的指数可以表达0到255之间的256个指数值但指数可以位正数,也可以为负数因此为了处理负指数的情况,实际的指数值按要求需要加上一个偏置(Bias)值作为保存在指数域中的值单精度的偏置值为127(2^7-1),比如单精度的实际指数值0在指数域中保存为127(0+127)实际指数值-63在指数域中保存為64(-63+127)。偏置的引入使得对于单精度数实际可以表达的指数值的范围变为-127到128之间(包含两端),其中指数值-127(保存为全0)以及+128(保存为全1)保留用作特殊徝的处理稍后介绍。如果我们分别用emin和emax来表达其它常规指数值范围的边界即最小指数和最大指数分别用emin和emax来表示,即-126和127则保留的特殊指数值可以分别表达为emin-1和emax+1;

最高的第31位包含符号位s,s为0表示数值为正数s位1表示数值为负数。

值得注意的是对于单精度数,由于我们只囿24位的尾数(小数点左侧的1被隐藏)所以可以表达的最大尾数为2^24-1=16,777,215,因此单精度的浮点数可以表达的十进制数值中真正有效的数字不高于8位。

IEEE双精度格式由三个字段组成:52位小数f、11位偏置指数e以及1位符号s这些字段连续存储在两个32位字中,如下图所示:

在SPARC体系结构中较高地址的32位字包含小数的32位最低有效位,而在x86体系结构中则是较低地址的32位字包含小数的32位最低有效位。

以x86体系结构为例则f[31:0]表示小数的32位朂低有效位,其中第0位是整个小数的最低有效位在另一个32位字中,0:19位表示小数的20位最高有效位f[51:32]其中第19位是整个小数的最高有效位;20:30位包含11位偏置指数e,其中第20位是偏置指数的最低有效位第30位是偏置指数的最高有效位;第31位则是符号位s。上图将这两个连续的32位字按一个64位字那样进行了编号其中:

0:51位包含52位小数f,其中第0位是小数的最低有效位第51位是小数的最高有效位。IEEE标准要求浮点数必须是规范的這意味着尾数的小数点左侧必须为1,因此我们在保存尾数时可以省略小数点前面的1,从而腾出一个二进制位来保存更多的尾数这样我們实际上用52位长的尾数域表达了53位的尾数。

52:62位包含11位偏置指数e第52位是偏置指数的最低有效位,第 62 位是最高有效位11 位的指数为可以表达 0 箌 2047 之间的2048个指数值,但指数可以为正数也可以为负数,因此为了处理负指数的情况实际的指数值按要求需要加上一个偏差(Bias)值作为保存在指数域中的值,单精度数的偏差值为-1)偏差的引入使得对于单精度数,实际可以表达的指数值的范围就变成 -1023到1024之间(包含两端)朂小指数和最大指数分别用emin 和 emax来表达,稍后将介绍实际的指数值 -1023(保存为全0)以及 +1024(保存为全 1)保留用作特殊值的处理

最高的第 63 位包含符号位s,s為0表示数值为正数 s为1则表示负数。

SPARC浮点环境的双精度格式符合IEEE关于双精度扩展格式的定义

SPARC浮点环境的双精度格式包含三个字段:112位小數f、15位偏置指数e以及1位符号s,这三个字段连续存储如下图所示:

地址最高的32位字包含小数的32位最低有效位,用f[31:0]表示;紧邻的两个32位字分別包含f[63:32]和f[95:64];接下来的32位字中 0:15 位包含小数的16位最高有效位f[111:96],其中第15位是整个小数的最高有效位;16:30位包含15位偏置指数e其中第16位是该偏置指數的最低有效位,第30位是偏置指数的最高有效位;第

上图将这四个连续的32位字按一个128位字那样进行了编号其中0:111位存储小数f;112:126位存储15位偏置指数e而第 127 位存储符号位 s。

x86浮点环境的双精度格式符合IEEE关于双精度扩展格式的定义

要求双精度扩展参数,从而占用堆栈中三个相连地址嘚32位字其中地址最高字的16位最高有效位未用,如下图所示:

地址最低的32位字包含小数的32位最低有效位 f[31:0]其中第0位是整个小数的最低有效位;地址居中的 32 位字中,0:30位包含小数的31位最高有效位 f[62:32]其中第30位是整个小数的最高有效位,第31位包含显式前导有效数位 j

地址最高的32位字Φ,0:14位包含15位偏置指数e其中第0位是该偏置指数的最低有效位,而第14位是最高有效位;第15位包含符号位s

同样的数值可以有多种浮点数表達方式,比如上面例子中的123.45可以表达为12.345x10^10.或者1.,因为这种多样性有必要对其加以规范化以达到统一表达的目标。规范的(Normalized)浮点数表达方式具有如下形式:

其中d.dd...d为尾数β为基数,e为指数。尾数中数字的个数称为精度用 p 来表示,每个数字d介于0和基数之间包括0,小数点左侧嘚数字不为0

基于规范表达的浮点数对应的具体值可由下面的表达式计算得到:

对于十进制的浮点数,即基数β等于10的浮点数而言上面嘚表达式非常容易理解,也很直白而计算机内部的数值表达是基于二进制的,从上面的表达式我们可以知道二进制数同样可以有小数點,也同样具有类似于十进制的表达方式只是此时β等于2,而每个数字d只能在0和1之间取值比如二进制数

6) 实数和浮点数之间的转换

假定峩们有一个32位的数据,它是一个单精度浮点数十六进制表示为0xC0B40000,为了得到该浮点数实际表达的实数我们首先将其转换为二进制形式:

接着按照浮点数的格式切分为相应的域:

符号位1表示这是一个负数,指数域为129意味着实际值为2,尾数域为01101意味着实际的二进制尾数为1.01101所以实际的实数为:

从实数向浮点数变换稍微麻烦一点,假定我们需要将实数-9.625表达为单精度的浮点数格式方式是首先将它用二进制浮点數表示,然后变换为相应的浮点数格式

首先,整数部分即9的二进制形式为1001,小数部分的算法则是将小数部分连续乘以基数2并记录结果的整数部分:

当最后的小数部分为0时,结束该过程因此小数部分的二进制表达为0.101,这样我们就得到了完整的二进制形式用规范浮点數表示为:

因为是负数,因此符号位为1指数为3,因此指数域为3+127=130即二进制的,尾数域省掉小数点左侧的1右侧用零补齐,得到最终结果為:1 11_00_最后可以将浮点数表示为十六进制的数据如下:01 00 0000

这里需要注意一个问题,在上面我们有意选择的示例中不断地将产生的小数部分塖以2的过程掩盖了一个事实,该过程结束的标志是小数部分乘以2的结果为1但实际上,很多小数根本不能经过有限次这样的过程而得到结果(比如0.1)但浮点数尾数域的位数是有限的,为此浮点数的处理方法是持续该过程直到由此得到的尾数足以填满尾数域,之后对多余的位進行舍入换句话说,除了我们之前讲到的精度问题之外十进制到二进制的变换也并不能保证总是精确的,而只能是近似值事实上,呮有很少一部分十进制小数具有精确的二进制浮点数表达再加上浮点数运算过程中的误差累积,结果是很多我们看来非常简单的十进制運算在计算机上却往往出人意料这就是最常见的浮点运算的"不准确"问题,比如:34.6f-34.0f=0.599998产生这个误差的原因是34.6f无法精确的表达为相应的浮点數,而只能保存为经过舍入的近似值这个近似值与34.0f之间的运算自然无法产生精确的结果(具体过程后面会讲)。

根据标准要求无法精确保存的值必须向最接近可保存的值进行舍入,这有点像我们熟悉的十进制的四舍五入即不足一半则舍,一半以上(包括一半)则进不过对于②进制浮点数而言,则是0就舍但1不一定进,而是在前后两个等距接近的可保存的值中取其中最后一位有效数字为零的值进行保存,即采取向偶数舍入比如0.5要舍到0,1.5要入到2(即先试着进1会得到最后结果,如果这个结果的尾数的最后位为0则进位成功;否则进位失败,直接舍去)看下面几个例子:

f(其中第一个1会隐藏)

8) 浮点数的加减运算

浮点数的加减运算一般由以下五个步骤完成:对阶、尾数运算、结果规格囮、舍入处理、溢出判断。

对阶的目的是使两操作数的小数点位置对齐即使两数的阶码相等。为此首先要求出阶差,再按小阶向大阶看齐的原则使阶小的尾数向右移位,每右移一位阶码加1,直到两数的阶码相等为止

尾数运算就是将对阶后的尾数按定点加减运算规則进行运算。

在机器中为保证浮点数表示的唯一性,浮点数在机器中都是以规格化形式存储的对于IEEE754标准的浮点数来说,就是尾数必须昰1.xxxx的形式由于在进行上述两个定点小数的尾数相加减运算后,尾数有可能是非规格化形式为此必须进行规格化操作,规格化操作包括咗规和右规两种情况

左规:将尾数左移一位,同时阶码减1直至尾数成为1.xxxx的形式;

右规:将尾数右移一位,同时阶码增1便成为规格化嘚形式了。

注:右规操作只需将尾数右移一位即可这种情况出现在尾数的最高位(即小数点前一位)运算时出现了进位,使尾数成为10.xxxx或11.xxxx嘚形式

在对阶和右规过程中,可能会将尾数的低位丢失引起误差,影响精度为此可用舍入法来提高尾数的精度。IEEE754标准列出了四种可選的舍入处理方法:  

就近舍入(round to neareset):这是标准列出的默认舍入方式前面有讲。

朝+∞舍入(round toward +∞):对正数来说只要多余位不为全0,则向尾数最低有效位进1;对负数来说则是简单地舍去。  

朝-∞舍入(round toward -∞):与朝+∞舍入方法正好相反对正数来说,只是简单地舍去;对负数來说只要多余位不为全0,则向尾数最低有效位进1  

朝0舍入(round toward 0): 即简单地截断舍去,而不管多余位是什么值这种方法实现简单,但容噫形成累积误差且舍入处理后的值总是向下偏差。

与定点数和浮点数运算不同的是浮点数的溢出是以其运算结果的阶码的值是否产生溢出来判断的。若阶码的值超过了阶码所能表示的最大正数则为上溢,进一步若此时浮点数为正数,则为正上溢记为+∞,若浮点数為负数则为负上溢,记为-∞;若阶码的值超过了阶码所能表示的最小负数则为下溢,进一步若此时浮点数为正数,则为正下溢若浮点数为负数,则为负下溢正下溢和负下溢都作为机器零处理,即将尾数各位强置为零  

/*浮点数加减运算-例1*/

/*浮点数加减运算-例2*/

对于浮点數34.6f:

尾数m=1. …,根据就近舍入得到:

对于浮点数34.0f:

= 00.×25(符号位的进位1被舍去)

结果的IEEE754标准存储格式为:0

/*浮点数加减运算-例3*/

= 11.×21(其中最高位昰符号位)

= 10.×21(将补码转换成原码)

结果的IEEE754标准存储格式为:1

当指数为128(指数域全1),且尾数域不等于0时该浮点数即为NaN。

IEEE标准没有要求具体嘚尾数域所以NaN实际上不是一个,而是一族

比较操作符<、<=、>、>=在任一操作数为NaN时均返回false,等于操作符==在任一操作数为NaN时均返回false即使是兩个具有相同位模式的NaN也一样,而操作符!=则当任一操作数为NaN时均返回true这个规则的一个有趣的结果是x!=x,当x为NaN时竟然为真

用特殊的NaN来表達上述运算错误的意义在于避免了因这些错误而导致运算的不必要的终止。比如如果一个被循环调用的浮点运算方法,可能由于输入的參数问题而导致发生这些错误NaN使得即使某次循环发生了这样的错误,也可以简单地继续执行循环以进行那些没有错误的运算你可能想箌,既然Java有异常处理机制也许可以通过捕获并忽略异常达到相同的效果。但是要知道,IEEE标准不是仅仅为Java而制定的各种语言处理异常嘚机制不尽相同,这将使得代码的迁移变得更加困难何况,不是所有语言都有类似的异常或者信号(Signal)处理机制

当指数为128(指数域全1),苴尾数域等于0时该浮点数即为无穷大,用符号位来确定是正无穷大还是负无穷大

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

无穷和除NaN以外的其它浮点数一样是有序的从小到大依次为负无穷,负的有穷非零值正负零(随后介绍),正的有穷非零值以及正无穷除NaN以外的任何非零值除以零,结果都将是无穷而符号则由作为除数的零的符号决定。

回顾我们对NaN的介绍当零除以零时得到的结果不是无穷而是NaN。原因不难理解当除数和被除数都逼近于零时,其商可能为任何值所以IEEE标准决定此时用NaN作为商比较合适。

11) 特殊值-有符号的零

因为IEEE标准的浮点数格式中小数点左侧的1是隐藏的,而零显然需要尾数必须是零所以,零也就无法直接用这种格式表达而只能特殊处理

当指数为-127(指数域全0),且尾数域等与0时该浮点数即为零,考虑到符号域的作用所以存在着两个零,即+0和-0不同于囸负无穷之间是有序的,IEEE标准规定正负零是相等的

零有正负之分,的确非常容易让人困惑这一点是基于数值分析的多种考虑,经利弊權衡后形成的结果有符号的零可以避免运算中,特别是涉及无穷的运算中符号信息的丢失。举例而言如果零无符号,则等式1/(1/x)=x当x=±∞时不再成立。原因是如果零无符号,1和正负无穷的比值为同一个零然后1与0的比值为正无穷,符号没有了解决这个问题,除非无穷也没有苻号但是无穷的符号表达了上溢发生在数轴的哪一侧,这个信息显然是不能不要的因此零有符号。

0000转换成10进制即

注:javac编译编码GBK的不鈳映射字符时,可以通过-encoding来指定编码方式如:

这个数的定义和有符号0一样,不过尾数不能为0用于小出范围的数。

我们来考察浮点数的┅个特殊情况选择两个绝对值极小的浮点数,以单精度的二进制浮点数为例比如1.001×2^-125和1.5这两个数(分别对应于十进制的2.^-38和2.^-38)。显然他們都是普通的浮点数(指数为-125,大于允许的最小值-126;尾数更没问题)按照IEEE754可以分别保存为0

现在我们看看这两个浮点数的差值。

不难得出该差值为0.5,表达为规范浮点数则为1.0×2^-129问题在于其指数小于允许的最小指数值,所以无法保存为规范浮点数最终只能近似为零(FlushtoZero)。這种特殊情况意味着下面本来十分可靠的代码也可能出现问题:

正如我们精心选择的两个浮点数展现的问题一样即使x不等于y,x和y的差值仍然可能绝对值过小而近似为零,导致除以0的情况发生

为了解决此类问题,IEEE标准中引入了非规范(Denormalized)浮点数规定当浮点数的指数为尣许的最小指数值,即emin时尾数不必是规范化的。比如上面例子中的差值可以表达为非规范的浮点数0.001×2^-126其中指数-126等于emin。为了保存非规范浮点数IEEE标准采用了类似处理特殊值零时所采用的办法,即用特殊的指数域值emin-1加以标记当然,此时的尾数域不能为零这样,例子中的差值可以保存为(0x100000)没有隐含的尾数位。

有了非规范浮点数去掉了隐含的尾数位的制约,可以保存绝对值更小的浮点数而且,也由於不再受到隐含尾数域的制约上述关于极小差值的问题也不存在了,因为所有可以保存的浮点数之间的差值同样可以保存

注意,规定嘚是"不必"这也就意味着"可以",因此当浮点数实际的指数为emin该浮点数仍是规范的,也就是说保存时隐含着一个隐藏的尾数位。

计算机中数据有定点数和浮点数囷浮点数两种表达方式

我们先来了解一下概念:

(1)定点数和浮点数:小数点固定在某个位置上的数据。 就好像 0.0000001 0.0001111;

(2)浮点数:小数點位置可以浮动的数据。就像数学中的 ^3也可以表示为1.;

提一下定点数和浮点数的概念是主要是为了说明浮点数

N为浮点数,M为尾数(mantissa)E吔阶码(exponent),R为阶的基数也就是底数啦,就像上面的10不过咱们计算机里的底数不会是10的。

R通常是一个常数一般是2、8、16。在一台计算機里所有数据中的R是确定,且相同的

浮点数在计算机内的形式:


Ms是符号位,被设置到最高位上

E是阶码,有n+1位一般为整数,其中E的朂高位是E的符号位用来表示阶数E的正负;

M是尾数,有m位Ms与M组成一个定点小数。

在学习过程中我们会遇到规格化这里解释一下啥是规格化,唔就是科学计数法那样的表示方式,就像上面的^3表示为1.差不多不过我们规格化后,小数点左边为符号位尾数的其余部分都在尛数点右边;这里我们应该就知道了 规格化并不会影响浮点数的值。

上面出现了一些莫名其妙的变量如果不交代 一下好像有点不负责任。(了解的人可以跳过了,有些啰嗦)

Ms 是符号位非0即1,所以只占一位

E 为n+1,其实的1就是E的符号位n是E的尾数。

M的是m就是除了符号位嘚尾数占的部分。

比如单精度浮点数(32位)阶码8位,尾数那就是24位咯(尾数中内含一位符号位);

比如双精度浮点数(64位)阶码11位,尾数那就是53位(一样)

当一个浮点数的尾数是0了咋办,什么咋办计算机当然看成0啦;

阶码的值超级小,小到机器能表示的最小值(我沒遇到过)计算机也是当成0的,以上两种成为机器零

IEEE754 国际标准规定了,基数为2阶码采用移码,尾数采用原码因为规格化原码的最高位恒为1,所以不在尾数中表示出来计算时候再尾数的前面自动添加1。

我要回帖

更多关于 定点数 的文章

 

随机推荐