如何计算双精度和浮点数精度

13

我一直在努力寻找如何计算浮点数/双精度范围数字-3.402823e38..3.402823e38和-1.79769313486232e308..1.79769313486232e308。

对于int32,您会进行2 ^ 32 = 4294967296/2的运算,从而得到-2147483648到2147483647的范围。那么我该如何确定浮点数和双精度数的精度数字呢?我认为我正在搜索错误的术语,因为没有任何结果出现。


简短回答:双精度值(假设采用IEEE 754浮点数)的最大值为2^1024 * (1 - 2^-53)。单精度值的最大值为2^128 * (1 - 2^-24)。 - Mark Dickinson
4个回答

27

好的,实际上这两种类型看起来都像以下内容:

[sign] [exponent] [mantissa]

用以下形式表示数字:

  

[符号] 1.[尾数] × 2[指数]

其中指数和尾数的大小各不相同。对于 float 类型,指数有 8 位宽度,而 double 类型则有11位宽度。此外,指数使用无符号表示,具有一个称为偏移量的值,float为127,double为1023。这将使得 float 的指数范围为 -126 至 127,double 的指数范围为 -1022 至 1023。

指数是2某个数的指数,因此当计算2127时,您将获得1.7×1038,这将使您处于大约 float 最大值的范围内。类似地,double 可以获得9×10307

显然,这些数字并不完全符合我们的期望。这就是尾数发挥作用的地方。尾数表示一个始终以“1”开头的规格化二进制数(这就是规格化部分)。其余部分就是小数点后的数字。由于最大尾数近似为二进制中的1.111111111...,几乎等于2,因此我们得到了约为3.4×1038float 最大值和约为1.79×10308double 最大值。

[编辑 2011-01-06] 正如下面问题所述(以及问题下方),精确公式如下:

Formula to calculate the exact maximum value for an IEEE-754 floating-point type: 2^(2^(e-1) )⋅(1-2^(-p) )

其中 e 是指数位数,p 是尾数位数,包括前面提到的隐式位(由于规格化而产生)。该公式再次复制了我们上面看到的结果,但现在更精确了。第一个因子 22e − 1 是最大指数,乘以二(我们将此保存在第二个因子中)。第二个因子是我们可以表示的最大的小于一的数字。我曾经说过这个数字几乎是两个。由于在这个公式中我们将指数扩大了两倍,所以我们需要考虑这一点,现在得到的数字几乎是一。希望不会太困惑。

无论如何,对于 floate=8,p=24),我们得到精确值:340282346638528859811704183484516925440,大约为3.4×1038。对于 doublee=10,p=53),我们得到的精确值为:179769313486231570814527423731704356798070567525844996598917476803157260780028538760589558632766878171540458953514382464234321326889464182768467546703537516986049910576551282076245490090389328944075868508455133942304583236903222948165808559332123348274797826204144

 1.   1     0     1     1
 ↑    ↑     ↑     ↑     ↑
2^0  2^-1  2^-2  2^-3  2^-4
 =    =     =     =     =
 1   0.5   0.25  0.125 0.0625

因此,double尾数中的最后一位代表大约2.2×10−16或2−52的值,所以如果指数为1,则这是我们可以添加到该数字的最小值-使得double精度在16个十进制数字左右。同样适用于具有大约七个数字的float


需要指出的一件事是,“double”中指数部分是11位。http://en.wikipedia.org/wiki/Double_precision_floating-point_format - JASON
谢谢。我猜2的10次方的偏差让我有些困惑。顺便说一下,你也可以建议修改 :) - Joey
@Joey 根据《计算机科学家应该了解的浮点运算知识》(http://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html)所述,二进制浮点数中的前导1是float的24位尾数和double的53位尾数的一部分,正如你所说。然而,你在最后说双精度浮点数尾数的最后一位是2^-53,这是不正确的,因为2^-53是第54位,而双精度浮点数没有第54位。它应该是2^-52或约为2.22E-16。我将提交一个编辑请求,并请比我聪明的人验证它。 - Wandering Fool
我真的希望我错了,因为2^-53看起来更好。 - Wandering Fool
@WanderingFool:看起来你是对的。尽管评论者似乎没有任何关于这个主题的专业知识,但他们并不这么认为。我会加入你的编辑建议。 - Joey
显示剩余6条评论

0

-1

计算并不那么容易。这是因为浮点数和双精度数的实现方式不同。它们都被分成两部分:一部分用于基数,另一部分用于指数。我认为浮点数将24位分配给基数,8位分配给指数。但我对此并不确定!尽管如此,我将基于这个事实进行进一步的计算和假设,所以这些计算可能都是错误的,但它们说明了正确的原则。这些规格也可能因语言而异,即使有标准规定它们不应该。但在编程时不能把任何事情视为理所当然 :p

这意味着基数可以在-8388608和8388607之间,指数可以在-128和127之间。

然后当使用数字时,计算机会像这样思考:

基数 * 10^指数

这导致最大可能的数字是8388607 * 10 ^ 127,这将是...很多。但它将包含120个零,因为它不能指定超过7个数字。

随着数字的增长,数字的精度会降低。这意味着您的问题格式不正确 ;) 只有在您知道需要多少个正确小数位数时,才能为浮点数指定有效范围。如果您需要2个保证准确小数位的可能性,则浮点数的范围为-83885至83885。


−128 不是有效的指数,因为它们不以二进制补码存储,而是使用添加偏置的无符号方式存储。此外,零指数保留用于次正规数,进一步缩小了范围。另外,指数是针对基数2的,而不是10。并且尾数的工作方式也不同。 - Joey
好的,我忘了。谢谢你!我只是想要理解这个原则,即真正需要你程序目的所需的小数位数将是理解可实现范围的最终因素 :) (我应该一开始就写出来的,哈哈) - davogotland
一个非常令人困惑的答案。其次,指数(有偏或无偏)是以二的幂表示的。 - Olof Forshell
我按回车键太快了。这是一个非常令人混淆的答案。首先,使用24位,你可以表达从0到16777215之间的所有整数(给定适当的索引):如果值为负或正取决于符号位。其次,指数(是否偏差)以二的幂表示。第三,数字的精度并没有“降低”,仍然是7-8位数字。顺便说一下,16777215最容易说明具有7-8位精度:它显然处理所有7位数字(0-9999999),还有一部分8位范围(小)。因此是7-8位数字。 - Olof Forshell

-2

这只是在重申原帖中已经知道和提到的内容,但并没有解释这些数字是如何产生的。 - Joey

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接