热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

深入浅出浮点数(转)

深入浅出浮点数FloatingPointNumberInaNutshell深入浅出浮点数StephenSuenCopyright?2005StephenSuen.Allrights

深入浅出浮点数

Floating Point Number In a Nutshell

深入浅出浮点数

Stephen Suen

Copyright ?2005 Stephen Suen. All rights reserved.

浮点数(Floating PointNumber)计算机系统中用于表达实数或者说小数的一种方式。由于其表达方式的原因,产生了围绕浮点数的许多常见问题。最典型的就是"为什么我的浮点运算的结果和想象的不同",即浮点数精度损失问题。本文将回避关于浮点数枯燥的数值计算理论,基于Java平台的浮点数支持(当然,也适用于其它绝大部分编程语言),尽可能深入浅出的介绍浮点数的基本知识,和常见问题产生的原因。

本文的最新版本将发布在程序员咖啡馆网站上(建设中)。同时欢迎订阅我们的邮件组,以获得关于本文的正式发布及更新信息。

全文在保证完整性,且保留全部版权声明(包括上述链接)的前提下可以在任意媒体转载——须保留此标注。


目录1. 什么是浮点数2. IEEE浮点数3. 实数和浮点数之间的变换4. 特殊值
4.1. NaN4.2. 无穷4.3. 有符号的零4.4. 非规范化数
5. 参考资料

1. 什么是浮点数

在计算机系统的发展过程中,曾经提出过多种方法表达实数。典型的比如相对于浮点数的定点数(FixedPointNumber)。在这种表达方式中,小数点固定的位于实数所有数字中间的某个位置。货币的表达就可以使用这种方式,比如99.00 或者 00.99可以用于表达具有四位精度(Precision),小数点后有两位的货币值。由于小数点位置固定,所以可以直接用四位数值来表达相应的数值。SQL中的 NUMBER数据类型就是利用定点数来定义的。还有一种提议的表达方式为有理数表达方式,即用两个整数的比值来表达实数。

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

提示:尾数有时也称为有效数字(Significand)。尾数实际上是有效数字的非正式说法。

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

±d.dd...d × βe , (0 ≤ di <β)

其中 d.dd...d 即尾数&#xff0c;β为基数&#xff0c;e为指数。尾数中数字的个数称为精度&#xff0c;在本文中用 p来表示。每个数字 d 介于 0 和基数之间&#xff0c;包括0。小数点左侧的数字不为 0。

基于规范表达的浮点数对应的具体值可由下面的表达式计算而得&#xff1a;

±(d 0 &#43; d1β-1 &#43; ... &#43; dp-1β-(p-1)e , (0 ≤ di <β)

对于十进制的浮点数&#xff0c;即基数 β 等于 10的浮点数而言&#xff0c;上面的表达式非常容易理解&#xff0c;也很直白。计算机内部的数值表达是基于二进制的。从上面的表达式&#xff0c;我们可以知道&#xff0c;二进制数同样可以有小数点&#xff0c;也同样具有类似于十进制的表达方式。只是此时β 等于 2&#xff0c;而每个数字 d 只能在 0 和 1之间取值。比如二进制数 1001.101 相当于 1 × 2 3 &#43; 0 ×22 &#43; 0 × 21 &#43; 1 × 20 &#43; 1 ×2-1 &#43; 0 × 2-2 &#43; 1 ×2-3&#xff0c;对应于十进制的 9.625。其规范浮点数表达为 1.001101× 23

 

2. IEEE 浮点数

计算机中是用有限的连续字节保存浮点数的。保存这些浮点数当然必须有特定的格式&#xff0c;Java平台上的浮点数类型 floatdouble 采纳了 IEEE 754 标准中所定义的单精度 32位浮点数和双精度 64 位浮点数的格式。

注意: Java 平台还支持该标准定义的两种扩展格式&#xff0c;即float-extended-exponent 和 double-extended-exponent扩展格式。这里将不作介绍&#xff0c;有兴趣的读者可以参考相应的参考资料。

在 IEEE标准中&#xff0c;浮点数是将特定长度的连续字节的所有二进制位分割为特定宽度的符号域&#xff0c;指数域和尾数域三个域&#xff0c;其中保存的值分别用于表示给定二进制浮点数中的符号&#xff0c;指数和尾数。这样&#xff0c;通过尾数和可以调节的指数&#xff08;所以称为"浮点"&#xff09;就可以表达给定的数值了。具体的格式参见下面的图例&#xff1a;

在上面的图例中&#xff0c;第一个域为符号域。其中 0 表示数值为正数&#xff0c;而 1则表示负数。

第二个域为指数域&#xff0c;对应于我们之前介绍的二进制科学计数法中的指数部分。其中单精度数为8 位&#xff0c;双精度数为 11 位。以单精度数为例&#xff0c;8 位的指数为可以表达 0 到255 之间的 255个指数值。但是&#xff0c;指数可以为正数&#xff0c;也可以为负数。为了处理负指数的情况&#xff0c;实际的指数值按要求需要加上一个偏差&#xff08;Bias&#xff09;值作为保存在指数域中的值&#xff0c;单精度数的偏差值为 127&#xff0c;而双精度数的偏差值为1023。比如&#xff0c;单精度的实际指数值 0 在指数域中将保存为127&#xff1b;而保存在指数域中的 64 则表示实际的指数值 -63。偏差的引入使得对于单精度数&#xff0c;实际可以表达的指数值的范围就变成 -127到 128 之间&#xff08;包含两端&#xff09;。我们不久还将看到&#xff0c;实际的指数值-127&#xff08;保存为 全 0&#xff09;以及 &#43;128&#xff08;保存为全1&#xff09;保留用作特殊值的处理。这样&#xff0c;实际可以表达的有效指数范围就在 -127和 127 之间。在本文中&#xff0c;最小指数和最大指数分别用eminemax 来表达。

图例中的第三个域为尾数域&#xff0c;其中单精度数为 23 位长&#xff0c;双精度数为 52位长。除了我们将要讲到的某些特殊值外&#xff0c;IEEE标准要求浮点数必须是规范的。这意味着尾数的小数点左侧必须为1&#xff0c;因此我们在保存尾数的时候&#xff0c;可以省略小数点前面这个1&#xff0c;从而腾出一个二进制位来保存更多的尾数。这样我们实际上用 23位长的尾数域表达了 24 位的尾数。比如对于单精度数而言&#xff0c;二进制的1001.101&#xff08;对应于十进制的 9.625&#xff09;可以表达为 1.001101 ×23&#xff0c;所以实际保存在尾数域中的值为00110100000000000000000&#xff0c;即去掉小数点左侧的 1&#xff0c;并用 0在右侧补齐。

值得注意的是&#xff0c;对于单精度数&#xff0c;由于我们只有 24位的指数&#xff08;其中一位隐藏&#xff09;&#xff0c;所以可以表达的最大指数为 224 -1 &#61; 16,777,215。特别的&#xff0c;16,777,216 是偶数&#xff0c;所以我们可以通过将它除以2 并相应地调整指数来保存这个数&#xff0c;这样 16,777,216同样可以被精确的保存。相反&#xff0c;数值 16,777,217则无法被精确的保存。由此&#xff0c;我们可以看到单精度的浮点数可以表达的十进制数值中&#xff0c;真正有效的数字不高于8 位。事实上&#xff0c;对相对误差的数值分析结果显示有效的精度大约为 7.22位。参考下面的示例&#xff1a;

true value stored value
--------------------------------------
16,777,215 1.6777215E7
16,777,216 1.6777216E7
16,777,217 1.6777216E7
16,777,218 1.6777218E7
16,777,219 1.677722E7
16,777,220 1.677722E7
16,777,221 1.677722E7
16,777,222 1.6777222E7
16,777,223 1.6777224E7
16,777,224 1.6777224E7
16,777,225 1.6777224E7
--------------------------------------

根据标准要求&#xff0c;无法精确保存的值必须向最接近的可保存的值进行舍入。这有点像我们熟悉的十进制的四舍五入&#xff0c;即不足一半则舍&#xff0c;一半以上&#xff08;包括一半&#xff09;则进。不过对于二进制浮点数而言&#xff0c;还多一条规矩&#xff0c;就是当需要舍入的值刚好是一半时&#xff0c;不是简单地进&#xff0c;而是在前后两个等距接近的可保存的值中&#xff0c;取其中最后一位有效数字为零者。从上面的示例中可以看出&#xff0c;奇数都被舍入为偶数&#xff0c;且有舍有进。我们可以将这种舍入误差理解为"半位"的误差。所以&#xff0c;为了避免7.22 对很多人造成的困惑&#xff0c;有些文章经常以 7.5位来说明单精度浮点数的精度问题。

提示: 这里采用的浮点数舍入规则有时被称为舍入到偶数&#xff08;RoundtoEven&#xff09;。相比简单地逢一半则进的舍入规则&#xff0c;舍入到偶数有助于从某些角度减小计算中产生的舍入误差累积问题。因此为IEEE 标准所采用。

3. 实数和浮点数之间的变换

现在我们已经明白了浮点数的 IEEE表达方式。我们来做些实数和浮点数之间的变换练习以加深理解。在这些练习中&#xff0c;你还会发现一些围绕浮点数运算的令人吃惊的事实。

首先我们来看看事情简单的一面&#xff0c;从浮点数变换到实数。理解了浮点数的格式&#xff0c;做这个练习并不难。假定我们有一个32 位的数据&#xff0c;用十六进制表示为0xC0B40000&#xff0c;并且我们知道它实际上是一个单精度的浮点数。为了得到该浮点数实际表达的实数&#xff0c;我们首先将它变换为二进制形式&#xff1a;

C 0 B 4 0 0 0 0
1100 0000 1011 0100 0000 0000 0000 0000

接着按照浮点数的格式切分为相应的域&#xff1a;

1 10000001 01101000000000000000000

符号域 1 意味着负数&#xff1b;指数域为 129 意味着实际的指数为 2&#xff08;减去偏差值 127&#xff09;&#xff1b;尾数域为 01101 意味着实际的二进制尾数为 1.01101&#xff08;加上隐含的小数点前面的 1&#xff09;。所以&#xff0c;实际的实数为&#xff1a;

-1.01101 × 22
-(20 &#43; 2-2 &#43; 2-3 2-5) × 22
-5.625

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

首先&#xff0c;将小数点左侧的整数部分变换为其二进制形式&#xff0c;9的二进制性形式为 1001。处理小数部分的算法是将我们的小数部分乘以基数2&#xff0c;记录乘积结果的整数部分&#xff0c;接着将结果的小数部分继续乘以2&#xff0c;并不断继续该过程&#xff1a;

0.625 × 2 &#61; 1.25 1
0.25 × 2 &#61; 0.5 0
0.5 × 2 &#61; 1 1
0

当最后的结果为零时&#xff0c;结束这个过程。这时右侧的一列数字就是我们所需的二进制小数部分&#xff0c;即0.101。这样&#xff0c;我们就得到了完整的二进制形式1001.101。用规范浮点数表达为 1.001101 × 23

因为是负数&#xff0c;所以符号域为 1。指数为 3&#xff0c;所以指数域为 3 &#43; 127 &#61;130&#xff0c;即二进制的 10000010。尾数省略掉小数点左侧的 1 之后为001101&#xff0c;右侧用零补齐。最终结果为&#xff1a;

1 10000010 00110100000000000000000

最后可以将浮点数形式表示为十六进制的数据如下&#xff1a;

1100 0001 0001 1010 0000 0000 0000 0000
C 1 1 A 0 0 0 0

最终结果为 0xC11A0000。

很简单&#xff1f;等等&#xff01;你可能已经注意到了&#xff0c;在上面这个我们有意选择的示例中&#xff0c;不断的将产生的小数部分乘以2 的过程掩盖了一个事实。该过程结束的标志是小数部分乘以 2 的结果为1&#xff0c;不难想象&#xff0c;很多小数根本不能经过有限次这样的过程而得到结果&#xff08;比如最简单的0.1&#xff09;。我们已经知道浮点数尾数域的位数是有限的&#xff0c;为此&#xff0c;浮点数的处理办法是持续该过程直到由此得到的尾数足以填满尾数域&#xff0c;之后对多余的位进行舍入。换句话说&#xff0c;除了我们之前讲到的精度问题之外&#xff0c;十进制到二进制的变换也并不能保证总是精确的&#xff0c;而只能是近似值。事实上&#xff0c;只有很少一部分十进制小数具有精确的二进制浮点数表达。再加上浮点数运算过程中的误差累积&#xff0c;结果是很多我们看来非常简单的十进制运算在计算机上却往往出人意料。这就是最常见的浮点运算的"不准确"问题。参见下面的 Java 示例&#xff1a;

System.out.print("34.6-34.0&#61;" &#43; (34.6f-34.0f));

这段代码的输出结果如下&#xff1a;

34.6-34.0&#61;0.5999985

产生这个误差的原因是 34.6无法精确的表达为相应的浮点数&#xff0c;而只能保存为经过舍入的近似值。这个近似值与34.0 之间的运算自然无法产生精确的结果。

 

4. 特殊值

通过前面的介绍&#xff0c;你应该已经了解的浮点数的基本知识&#xff0c;这些知识对于一个不接触浮点数应用的人应该足够了。不过&#xff0c;如果你兴趣正浓&#xff0c;或者面对着一个棘手的浮点数应用&#xff0c;可以通过本节了解到关于浮点数的一些值得注意的特殊之处。

我们已经知道&#xff0c;指数域实际可以表达的指数值的范围为 -127 到 128之间&#xff08;包含两端&#xff09;。其中&#xff0c;值 -127&#xff08;保存为 全 0&#xff09;以及 &#43;128&#xff08;保存为全1&#xff09;保留用作特殊值的处理。本节将详细 IEEE标准中所定义的这些特殊值。

浮点数中的特殊值主要用于特殊情况或者错误的处理。比如在程序对一个负数进行开平方时&#xff0c;一个特殊的返回值将用于标记这种错误&#xff0c;该值为NaN&#xff08;Not aNumber&#xff09;。没有这样的特殊值&#xff0c;对于此类错误只能粗暴地终止计算。除了NaN 之外&#xff0c;IEEE 标准还定义了 ±0&#xff0c;±∞ 以及非规范化数&#xff08;DenormalizedNumber&#xff09;。

对于单精度浮点数&#xff0c;所有这些特殊值都由保留的特殊指数值 -127 和 128来编码。如果我们分别用 eminemax来表达其它常规指数值范围的边界&#xff0c;即 -126 和127&#xff0c;则保留的特殊指数值可以分别表达为emin - 1 和emax &#43; 1; 。基于这个表达方式&#xff0c;IEEE标准的特殊值如下所示&#xff1a;

其中 f表示尾数中的小数点右侧的&#xff08;Fraction&#xff09;部分。第一行即我们之前介绍的普通的规范化浮点数。随后我们将分别对余下的特殊值加以介绍。

4.1. NaN

NaN 用于处理计算中出现的错误情况&#xff0c;比如 0.0 除以 0.0或者求负数的平方根。由上面的表中可以看出&#xff0c;对于单精度浮点数&#xff0c;NaN表示为指数为 emax &#43; 1 &#61;128&#xff08;指数域全为 1&#xff09;&#xff0c;且尾数域不等于零的浮点数。IEEE标准没有要求具体的尾数域&#xff0c;所以 NaN实际上不是一个&#xff0c;而是一族。不同的实现可以自由选择尾数域的值来表达NaN&#xff0c;比如 Java 中的常量 Float.NaN的浮点数可能表达为01111111110000000000000000000000&#xff0c;其中尾数域的第一位为 1&#xff0c;其余均为0&#xff08;不计隐藏的一位&#xff09;&#xff0c;但这取决系统的硬件架构。Java中甚至允许程序员自己构造具有特定位模式的 NaN 值&#xff08;通过 Float.intBitsToFloat()方法&#xff09;。比如&#xff0c;程序员可以利用这种定制的 NaN值中的特定位模式来表达某些诊断信息。

定制的 NaN 值&#xff0c;可以通过 Float.isNaN()方法判定其为 NaN&#xff0c;但是它和 Float.NaN 常量却不相等。实际上&#xff0c;所有的NaN 值都是无序的。数值比较操作符 <&#xff0c;<&#61;&#xff0c;> 和 >&#61;在任一操作数为 NaN 时均返回 false。等于操作符 &#61;&#61; 在任一操作数为 NaN 时均返回false&#xff0c;即使是两个具有相同位模式的 NaN也一样。而操作符 !&#61; 则当任一操作数为 NaN 时返回 true。这个规则的一个有趣的结果是 x!&#61;x 当 x 为 NaN 时竟然为真。

可以产生 NaN 的操作如下所示&#xff1a;

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

注意: Java 中&#xff0c;不同于浮点数的处理&#xff0c;整数的 0 除以 0 将抛出java.lang.ArithmeticException 异常。

4.2. 无穷

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

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

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

4.3. 有符号的零

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

实际上&#xff0c;零保存为尾数域为全为 0&#xff0c;指数域为emin - 1 &#61;-127&#xff0c;也就是说指数域也全为0。考虑到符号域的作用&#xff0c;所以存在着两个零&#xff0c;即 &#43;0 和-0。不同于正负无穷之间是有序的&#xff0c;IEEE 标准规定正负零是相等的。

零有正负之分&#xff0c;的确非常容易让人困惑。这一点是基于数值分析的多种考虑&#xff0c;经利弊权衡后形成的结果。有符号的零可以避免运算中&#xff0c;特别是涉及无穷的运算中&#xff0c;符号信息的丢失。举例而言&#xff0c;如果零无符号&#xff0c;则等式 1/(1/x)&#61; x 当x &#61; ±∞ 时不再成立。原因是如果零无符号&#xff0c;1和正负无穷的比值为同一个零&#xff0c;然后 1 与 0的比值为正无穷&#xff0c;符号没有了。解决这个问题&#xff0c;除非无穷也没有符号。但是无穷的符号表达了上溢发生在数轴的哪一侧&#xff0c;这个信息显然是不能不要的。零有符号也造成了其它问题&#xff0c;比如当 x&#61;y 时&#xff0c;等式1/x &#61; 1/y 在 x 和 y 分别为 &#43;0 和-0时&#xff0c;两端分别为正无穷和负无穷而不再成立。当然&#xff0c;解决这个问题的另一个思路是和无穷一样&#xff0c;规定零也是有序的。但是&#xff0c;如果零是有序的&#xff0c;则即使if (x&#61;&#61;0) 这样简单的判断也由于 x 可能是±0 而变得不确定了。两害取其轻者&#xff0c;零还是无序的好。

4.4. 非规范化数

我们来考察浮点数的一个特殊情况。选择两个绝对值极小的浮点数&#xff0c;以单精度的二进制浮点数为例&#xff0c;比如1.001 × 2-125 和 1.0001 × 2-125这两个数&#xff08;分别对应于十进制的 2.6448623 × 10-38 和2.4979255 × 10-38&#xff09;。显然&#xff0c;他们都是普通的浮点数&#xff08;指数为 -125&#xff0c;大于允许的最小值-126&#xff1b;尾数更没问题&#xff09;&#xff0c;按照 IEEE 754 可以分别保存为00000001000100000000000000000000&#xff08;0x1100000&#xff09;和00000001000010000000000000000000&#xff08;0x1080000&#xff09;。

现在我们看看这两个浮点数的差值。不难得出&#xff0c;该差值为 0.0001 ×2-125&#xff0c;表达为规范浮点数则为 1.0 ×2-129。问题在于其指数大于允许的最小指数值&#xff0c;所以无法保存为规范浮点数。最终&#xff0c;只能近似为零&#xff08;FlushtoZero&#xff09;。这中特殊情况意味着下面本来十分可靠的代码也可能出现问题&#xff1a;

if (x !&#61; y) {
z &#61; 1 / (x -y);
}

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

为了解决此类问题&#xff0c;IEEE标准中引入了非规范&#xff08;Denormalized&#xff09;浮点数。规定当浮点数的指数为允许的最小指数值&#xff0c;即emin时&#xff0c;尾数不必是规范化的。比如上面例子中的差值可以表达为非规范的浮点数0.001 × 2-126&#xff0c;其中指数 -126 等于emin。注意&#xff0c;这里规定的是"不必"&#xff0c;这也就意味着"可以"。当浮点数实际的指数为emin&#xff0c;且指数域也为emin时&#xff0c;该浮点数仍是规范的&#xff0c;也就是说&#xff0c;保存时隐含着一个隐藏的尾数位。为了保存非规范浮点数&#xff0c;IEEE标准采用了类似处理特殊值零时所采用的办法&#xff0c;即用特殊的指数域值emin - 1加以标记&#xff0c;当然&#xff0c;此时的尾数域不能为零。这样&#xff0c;例子中的差值可以保存为00000000000100000000000000000000&#xff08;0x100000&#xff09;&#xff0c;没有隐含的尾数位。

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

 

5. 参考资料

  • Java Language Specification, Third Edition

  • David Goldberg, What Every ScientistShould Know About Floating-Point Arithmetic

  • Brian Goetz, Java theory and practice: Where’s your point?





欢迎您使用http://Blogmove.cn提供的"博客搬家"和"博文三窟"服务.

推荐阅读
  • 在 Linux 环境下,多线程编程是实现高效并发处理的重要技术。本文通过具体的实战案例,详细分析了多线程编程的关键技术和常见问题。文章首先介绍了多线程的基本概念和创建方法,然后通过实例代码展示了如何使用 pthreads 库进行线程同步和通信。此外,还探讨了多线程程序中的性能优化技巧和调试方法,为开发者提供了宝贵的实践经验。 ... [详细]
  • 通过利用代码自动生成技术,旨在减轻软件开发的复杂性,缩短项目周期,减少冗余代码的编写,从而显著提升开发效率。该方法不仅能够降低开发人员的工作强度,还能确保代码的一致性和质量。 ... [详细]
  • 数字图书馆近期展出了一批精选的Linux经典著作,这些书籍虽然部分较为陈旧,但依然具有重要的参考价值。如需转载相关内容,请务必注明来源:小文论坛(http://www.xiaowenbbs.com)。 ... [详细]
  • CTF竞赛中文件上传技巧与安全绕过方法深入解析
    CTF竞赛中文件上传技巧与安全绕过方法深入解析 ... [详细]
  • 本文介绍了UUID(通用唯一标识符)的概念及其在JavaScript中生成Java兼容UUID的代码实现与优化技巧。UUID是一个128位的唯一标识符,广泛应用于分布式系统中以确保唯一性。文章详细探讨了如何利用JavaScript生成符合Java标准的UUID,并提供了多种优化方法,以提高生成效率和兼容性。 ... [详细]
  • 帝国CMS中的信息归档功能详解及其重要性
    本文详细解析了帝国CMS中的信息归档功能,并探讨了其在内容管理中的重要性。通过归档功能,用户可以有效地管理和组织大量内容,提高网站的运行效率和用户体验。此外,文章还介绍了如何利用该功能进行数据备份和恢复,确保网站数据的安全性和完整性。 ... [详细]
  • Web开发框架概览:Java与JavaScript技术及框架综述
    Web开发涉及服务器端和客户端的协同工作。在服务器端,Java是一种优秀的编程语言,适用于构建各种功能模块,如通过Servlet实现特定服务。客户端则主要依赖HTML进行内容展示,同时借助JavaScript增强交互性和动态效果。此外,现代Web开发还广泛使用各种框架和库,如Spring Boot、React和Vue.js,以提高开发效率和应用性能。 ... [详细]
  • 2018 HDU 多校联合第五场 G题:Glad You Game(线段树优化解法)
    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6356在《Glad You Game》中,Steve 面临一个复杂的区间操作问题。该题可以通过线段树进行高效优化。具体来说,线段树能够快速处理区间更新和查询操作,从而大大提高了算法的效率。本文详细介绍了线段树的构建和维护方法,并给出了具体的代码实现,帮助读者更好地理解和应用这一数据结构。 ... [详细]
  • 触发器的稳态数量分析及其应用价值
    本文对数据库中的SQL触发器进行了稳态数量的详细分析,探讨了其在实际应用中的重要价值。通过研究触发器在不同场景下的表现,揭示了其在数据完整性和业务逻辑自动化方面的关键作用。此外,还介绍了如何在Ubuntu 22.04环境下配置和使用触发器,以及在Tomcat和SQLite等平台上的具体实现方法。 ... [详细]
  • 在当前的软件开发领域,Lua 作为一种轻量级脚本语言,在 .NET 生态系统中的应用逐渐受到关注。本文探讨了 Lua 在 .NET 环境下的集成方法及其面临的挑战,包括性能优化、互操作性和生态支持等方面。尽管存在一定的技术障碍,但通过不断的学习和实践,开发者能够克服这些困难,拓展 Lua 在 .NET 中的应用场景。 ... [详细]
  • C++ 开发实战:实用技巧与经验分享
    C++ 开发实战:实用技巧与经验分享 ... [详细]
  • 在洛谷 P1344 的坏牛奶追踪问题中,第一问要求计算最小割,而第二问则需要找到割边数量最少的最小割。通过为每条边附加一个单位权值,可以在求解最小割时优先选择边数较少的方案,从而同时解决两个问题。这种策略不仅简化了问题的求解过程,还确保了结果的最优性。 ... [详细]
  • 在编程笔试和面试中,全排列算法因其适中的难度而备受青睐,不仅能够考察应聘者的算法基础,还能测试其对递归和回溯的理解。本文将深入解析全排列算法的实现原理,探讨其应用场景,并提供优化建议,帮助读者更好地掌握这一重要算法。 ... [详细]
  • 蓝桥杯算法实战:节点选取策略优化分析
    本文针对蓝桥杯算法竞赛中的节点选取策略进行了深入分析与优化。通过对比不同节点选择方法的效果,提出了基于贪心算法和动态规划的综合优化方案,旨在提高算法效率和准确性。实验结果表明,该优化策略在处理大规模数据集时表现出色,显著提升了算法性能。 ... [详细]
  • 2018年9月21日,Destoon官方发布了安全更新,修复了一个由用户“索马里的海贼”报告的前端GETShell漏洞。该漏洞存在于20180827版本的某CMS中,攻击者可以通过构造特定的HTTP请求,利用该漏洞在服务器上执行任意代码,从而获得对系统的控制权。此次更新建议所有用户尽快升级至最新版本,以确保系统的安全性。 ... [详细]
author-avatar
没有那么一个人_382
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有