书中说c标准提供了六个有效数字的浮点精度,但这不是真的吗?

时间:2019-01-31 22:41:14

标签: c floating-point

我正在阅读Stephen Prata的C Primer Plus,它介绍浮点数的第一种方式是谈论浮点数在某一点上的准确性。它专门说:“ C标准规定,浮点数必须能够表示至少六个有效数字...浮点数必须准确表示前六个数字,例如33.333333”

这对我来说很奇怪,因为它听起来像是浮点数,精确到六位数,但这是不正确的。 1.4存储为1.39999 ...,依此类推。您仍然有错误。

那么到底提供了什么?对于数字应该有多精确,是否存在临界点?

在C语言中,如果没有得到编译器警告,则不能在浮动中存储六个以上的有效数字,但是为什么呢?如果您要执行的数字超过六位数,那么看来准确无误。

下溢和次正规数部分使这一点更加混乱。如果您有一个最小的浮点数,然后将其除以10,那么得到的错误似乎就不正常了吗?它们似乎只是上面提到的常规舍入错误。

那么,为什么书中说的浮点数精确到六位数,并且次正规数与常规舍入误差有何不同?

2 个答案:

答案 0 :(得分:6)

假设您有一个带有 q 有效数字的十进制数字:

  

d q −1 d q −2 d q −3 ... d 0

,我们也将其设为浮点十进制数字,这意味着我们将其乘以十的幂:

  

d q −1 d q −2 d q −3 d 0 •10 e

接下来,我们将此数字转换为floatfloat中无法精确表示许多此类数字,因此我们将结果四舍五入到最接近的可表示值。 (如果出现平局,我们将四舍五入以使低位数字保持偶数。)结果(如果我们没有上溢或下溢)是某个浮点数 x 。通过浮点数的定义(在C 2018 5.2.4.2.2 3中),它由某个底数中的某个数字表示,该数字被该底数缩放为幂。假设它是第二个基数, x 是:

  

b p −1 b p −2 b p −3 b 0 •2 p

接下来,我们将此float x 转换回有效位数为 q 的十进制。同样,float x 可能无法精确地表示为带有 q 数字的十进制数字,因此我们得到了一些可能的新数字:

  

n q −1 n q −2 n q −3 ... n 0 •10 m

事实证明,对于任何float格式,都有一些数字 q ,这样,如果我们以十进制数字开头的字符仅限于 q 位数,则此往返转换的结果将等于原始数字。每个 q 个十进制数字在四舍五入到float之后又返回到 q 十进制数字时,都会得出起始数字。

在2018 C标准中,第5.2.4.2.2条第12款告诉我们该数字 q 必须至少为6(C实现可能支持更大的值),并且C实现应该为其定义float.h中的预处理器符号(在FLT_DIG中。

因此,考虑到您的示例编号1.4,当我们将其转换为IEEE-754基本32位二进制格式的float时,我们得到的精确值为1.39999997615814208984375(这是其数学值,为方便起见以十进制显示;对象中的实际位用二进制表示)。当我们将其完全转换为十进制时,将得到“ 1.39999997615814208984375”。但是,如果将其转换为四舍五入的十进制十进制数,则得到“ 1.40000”。因此1.4在往返中幸存下来。

换句话说,通常{strong>不正确可以在float中表示六个十进制数字而没有变化,但是float确实带有足够的信息,您可以从中恢复六个小数位。

当然,一旦开始进行算术运算,错误通常会加重,并且您不再可以依靠六个十进制数字。

答案 1 :(得分:3)

感谢Govind Parmar引用了C11(或就此而言为C99)的在线示例。

您所指的“ 6”是“ FLT_DECIMAL_DIG”。

  

http://c0x.coding-guidelines.com/5.2.4.2.2.html

     

十进制数字n,这样任何浮点数都带有   p个基数b位数可以用n舍入为浮点数   十进制数字,然后再次返回而不更改值,

  { p log10 b        if b is a power of 10
  {
  { [^1 + p log10 b^] otherwise
     

FLT_DECIMAL_DIG 6
  DBL_DECIMAL_DIG 10 LDBL_DECIMAL_DIG   10

“超自然”是指:

  

What is a subnormal floating point number?

     

当指数位为零且尾数为0时,数字是次正规的   不为零。它们是介于零和最小法线之间的数字   数。他们在尾数中没有隐含的前导1。


强烈建议:

如果您不熟悉“浮点算术”(或者坦率地说,即使您不熟悉),这也是阅读(或阅读)的出色文章:

What Every Programmer Should Know About Floating-Point Arithmetic