浮点精度是可变的还是不变的?

我不断得到浮点数( floatdouble floatlong double float )是否只有一个精度值,或者精度值是否可以变化的混合答案。

一个称为浮点与双精度的主题似乎意味着浮点精度是绝对的。

然而,另一个称为float和double之间的区别的话题是,

通常情况下,double有15到16个十进制数字的精度

另有消息称,

浮点类型的变量通常具有 7位有效数字的精度

类型double的变量通常具有 16位有效数字的精度

如果我使用的敏感代码在我的值不精确时很容易中断,我不喜欢引用上述近似值。 所以让我们直接记录。 浮点精度是可变的还是不变的,为什么?


精度是固定的,对于双精度来说精确度为53个二进制数字 (如果我们排除隐含的前导1,则精度为52)。 这出来大约十五位十进制数字


OP要求我详细说明为什么只有53个二进制数字意味着“大约”15个十进制数字。

为了直观地理解这一点,我们考虑一个不太精确的浮点格式:而不是像双精度数字那样的52位尾数,我们将使用4位尾数。

因此,每个数字将如下所示:(-1)s×2yyy×1.xxxx(其中s是符号位, yyy是指数, 1.xxxx是标准化尾数)。 对于直接讨论,我们只关注尾数而不是符号或指数。

下面是所有xxxx值的1.xxxx样式表(所有舍入为半到平均值,就像默认浮点舍入模式的工作方式一样):

  xxxx  |  1.xxxx  |  value   |  2dd  |  3dd  
--------+----------+----------+-------+--------
  0000  |  1.0000  |  1.0     |  1.0  |  1.00
  0001  |  1.0001  |  1.0625  |  1.1  |  1.06
  0010  |  1.0010  |  1.125   |  1.1  |  1.12
  0011  |  1.0011  |  1.1875  |  1.2  |  1.19
  0100  |  1.0100  |  1.25    |  1.2  |  1.25
  0101  |  1.0101  |  1.3125  |  1.3  |  1.31
  0110  |  1.0110  |  1.375   |  1.4  |  1.38
  0111  |  1.0111  |  1.4375  |  1.4  |  1.44
  1000  |  1.1000  |  1.5     |  1.5  |  1.50
  1001  |  1.1001  |  1.5625  |  1.6  |  1.56
  1010  |  1.1010  |  1.625   |  1.6  |  1.62
  1011  |  1.1011  |  1.6875  |  1.7  |  1.69
  1100  |  1.1100  |  1.75    |  1.8  |  1.75
  1101  |  1.1101  |  1.8125  |  1.8  |  1.81
  1110  |  1.1110  |  1.875   |  1.9  |  1.88
  1111  |  1.1111  |  1.9375  |  1.9  |  1.94

你说这个数字有多少个小数位? 你可以说2,因为在两位十进制数字范围内的每个值都被覆盖,尽管不是唯一的; 或者你可以说3,它涵盖了所有的唯一值,但不提供三位十进制数字范围内所有值的覆盖范围。

为了说明起见,我们会说它有2个十进制数字:小数精度将是可以表示这些十进制数字的所有值的位数。


好吧,那么,如果我们将所有数字减半(所以我们使用yyy = -1)会发生什么?

  xxxx  |  1.xxxx  |  value    |  1dd  |  2dd  
--------+----------+-----------+-------+--------
  0000  |  1.0000  |  0.5      |  0.5  |  0.50
  0001  |  1.0001  |  0.53125  |  0.5  |  0.53
  0010  |  1.0010  |  0.5625   |  0.6  |  0.56
  0011  |  1.0011  |  0.59375  |  0.6  |  0.59
  0100  |  1.0100  |  0.625    |  0.6  |  0.62
  0101  |  1.0101  |  0.65625  |  0.7  |  0.66
  0110  |  1.0110  |  0.6875   |  0.7  |  0.69
  0111  |  1.0111  |  0.71875  |  0.7  |  0.72
  1000  |  1.1000  |  0.75     |  0.8  |  0.75
  1001  |  1.1001  |  0.78125  |  0.8  |  0.78
  1010  |  1.1010  |  0.8125   |  0.8  |  0.81
  1011  |  1.1011  |  0.84375  |  0.8  |  0.84
  1100  |  1.1100  |  0.875    |  0.9  |  0.88
  1101  |  1.1101  |  0.90625  |  0.9  |  0.91
  1110  |  1.1110  |  0.9375   |  0.9  |  0.94
  1111  |  1.1111  |  0.96875  |  1.   |  0.97

按照与之前相同的标准,我们现在处理1个十进制数字。 所以你可以看到,取决于指数,你可以有更多或更少的十进制数字,因为二进制和十进制浮点数不会互相干净地映射

相同的参数适用于双精度浮点数(使用52位尾数),只有在这种情况下,您将得到15或16位十进制数,具体取决于指数。


所有现代计算机都使用二进制浮点运算。 这意味着我们有一个二进制尾数,其单精度通常为24位,双精度为53位,扩展精度为64位。 (扩展精度可用于x86处理器,但不适用于ARM或其他类型的处理器。)

24,53和64位mantissas意味着对于2k和2k + 1之间的浮点数,下一个更大的数字分别是2k-23,2k-52和2k-63。 这是决议。 每个浮点运算的舍入误差至多是其中的一半。

那么如何转换成十进制数? 这取决于。

取k =0,1≤x<2。分辨率分别为2-23,2-52和2-63,分别约为1.19×10-7,2.2×10-16和1.08×10-19。 这比小数7,16和19小一点。 然后取k = 3和
8≤x<16.两个浮点数之间的差异现在是8倍大。 对于8≤x <10,分别只有6以上,小于15以及18以上的小数点。 但是对于10≤x<16,你还会得到一位小数!

如果x仅比2k + 1少一点,并且只有一点多于10n,例如1000≤x<1024,则可以得到最高的小数位数。如果x高一点,则得到最小的小数位数大于2k且小于10n,例如1/1024≤x<1/1000。 相同的二进制精度可以产生小数精度,其变化高达1.3位或log10(2×10)。

当然,你可以阅读文章“每个计算机科学家应该知道的关于浮点运算的知识”。


使用其硬件协处理器(最初为8087)的80x86代码提供三种精度级别:32位,64位和80位。 那些非常严格遵循1985年的IEEE-754标准。最近的标准规定了128位格式。 浮点格式具有24,53,65和113个尾数位,它们对应于精度的7.22,15.95,19.57和34.02十进制数字。

公式是mantissa_bits / log_2 10,其中10的日志基数是3.321928095。

虽然任何特定实现的精度不会改变,但浮点值转换为十进制时可能会出现这种情况。 请注意,值0.1没有精确的二进制表示。 这是一个重复的位模式(0.0001100110011001100110011001100 ...),就像我们习惯的小数点,0.3333333333333约为1/3。

许多语言通常不支持80位格式。 有些C编译器可能会提供long double ,它使用80位浮点数或128位浮点数。 唉,它也可能使用64位浮点数,具体取决于实现。

NPU具有80位寄存器,并使用完整的80位结果执行所有操作。 在NPU堆栈内计算的代码可以从这种额外的精度中受益。 不幸的是,糟糕的代码生成 - 或者写得不好的代码 - 可能会通过将中间计算存储在32位或64位变量中来截断或舍入中间计算。

链接地址: http://www.djcxy.com/p/78619.html

上一篇: Is floating point precision mutable or invariant?

下一篇: C++ different output in double and float