【问题标题】:Precision in C floatsC 浮点数的精度
【发布时间】:2012-03-19 06:09:30
【问题描述】:

通常我们说浮点数的精度为小数点后 6 位。但是如果我们存储大量 10^30 的顺序,我们将不会得到小数点后 6 位。那么说浮点数精度为小数点后6位是否正确?

【问题讨论】:

标签: c floating-point precision


【解决方案1】:

“小数点后6位”是废话,你的例子很好地证明了这一点。

Thisfloat 数据类型的精确规范。

float 的精度为 24 位。根据在线资料,有 23 位表示二进制点之后的分数,此外还有一个“隐式前导位”。这总共给出了 24 个有效位。

因此在十进制数字中,这大约是:

24 * log(2) / log(10) = 7.22

【讨论】:

  • 谢谢。这解决了我在 CS 实验室中与 TA 的争论。
  • 计算有点不正确,因为有 24 个有效位精度(请参阅您的链接)。一旦你纠正它,我会给你一个赞成票:)
  • @Timothy Jones:哎呀,你是对的。我无意中读到了这篇文章
  • 只要你的十进制浮点值可以用有限精度二进制浮点数精确表示。
【解决方案2】:

听起来您是在询问decimal places(小数点后的数字)的精度,而significant figures(不包括前导零和尾随零的总位数)是描述数字准确性的更好方法。

您是正确的,小数点后的位数会随着数字变大而改变 - 但如果我们说的是精度,那么当数字变大时,有效数字的位数不会改变。然而,十进制数的答案并不简单:


如今,大多数系统都使用IEE floating point format 来表示 C 中的数字。但是,如果您遇到不寻常的事情,则值得检查一下。单精度 IEE float 数字由三部分组成:

  • 符号位(这个数字是正数还是负数)
  • (通常也是有符号的)指数
  • 分数(应用指数之前的数字)

正如我们所料,这一切都以二进制形式存储。


有多少位有效数字?

如果您使用的是 IEE-754 数字,“有多少有效数字”可能不是一个容易考虑的方法,因为精度是用二进制有效数字而不是十进制来衡量的floats 的小数部分只有 23 位精度,但是因为有一个隐含的前导位(除非小数部分全为零,表示最终值为 1),所以有 24 位有效精度。

这意味着有 24 个有效的二进制数字,它不能转换为十进制有效数字的确切数量。您可以使用公式 24 * log(2) / log(10) 来确定有 7.225 位十进制精度,这不是您问题的一个很好的答案,因为有 24 个有效二进制数字有 6 位有效小数位。

因此,单精度浮点数具有6-9 位精度的有效十进制数字,具体取决于数字。

有趣的是,您还可以使用此精度计算出可以成功表示为单精度浮点数的最大连续整数(从零开始计数)。它是 2^24 或 16,777,216。您可以精确存储更大的整数,但前提是它们可以用 24 位有效二进制数字表示。


更多琐事:分数组件的有限大小与 Javascript 中导致此问题的原因相同:

> console.log(9999999999999999);
10000000000000000

Javascript 数字始终表示为双精度浮点数,其精度为 53 位。这意味着在 2^53 和 2^54 之间,只能表示偶数,因为任何奇数的最后一位都会丢失。

【讨论】:

    【解决方案3】:

    浮点数的精度应该以二进制数字而不是十进制数字来衡量。这是因为计算机对二进制数进行运算,而二进制小数只能近似小数。

    语言律师会说 float 的确切宽度未由 C 标准指定,因此取决于实现,但在任何平台上,您都可能遇到 C float 表示 IEEE754 single-precision号码。

    IEEE754 指定浮点数在scientific notation 中:(-1)s×2e×m
    其中 s 为 1 位宽,e 为 8 位宽,m 为 23 位宽。在数学上,m 是 24 位宽,因为它总是假设最高位是 1。

    因此,可以用这种表示近似的十进制数字的最大数量是:log10(224) = 7.22。 这近似于七位有效十进制数字,以及从 2-126 到 2127 的指数。

    请注意,指数是单独测量的。这就像你使用普通的scientific notation,比如“一个人重 72.3 公斤 = 7.23×104 克”。注意这里有三个有效数字,表示这个数字只精确到100克以内。但也有一个完全不同的数字 exponent。你可以有一个非常大的指数,有效数字很少,比如“太阳重 1.99×1033 克”。大数字,几位数。

    【讨论】:

    • 语言学徒注意:有一些奇异的平台,其中 C 浮点不是 IEEE754 单,但如果 OP 正在处理它们,OP 已经知道这个问题的答案。在这里讨论 IBM/370 会造成不必要的混乱。
    • 更多语言迂腐:“二进制数字”是矛盾的,因为“数字”来自拉丁词“十”;这就是发明“位”一词来代替“二进制数字”一词的原因之一。不过,在这里对此不屑一顾会适得其反,因为有必要强调“位”的“二进制数字”意义。
    • @Crashworks:异国情调?尝试 VAX 或 Alpha,今天在我的公司非常活跃。很多东西仍在运行(维护跨平台代码非常痛苦)。
    • @phoog 一位没有写 cmets 声誉的新用户写道:很遗憾,您的“更多语言迂腐”是不正确的:digit 不是来自拉丁文 10:它的词根是 lating digitus,意思是手指。用手代表数字,“数字”的隐喻使用是绝对正确的。你可能是指十进制,它的拉丁词根“decem”是十。
    【解决方案4】:

    简而言之,一个浮点数可以存储大约 7-8 个有效的十进制数字。让我用一个例子来说明这一点:

    1234567001.00
             ^
             +---------------- this information is lost
    
    .01234567001
               ^ 
               +-------------- this information is lost
    

    基本上,浮点数存储两个值:1234567 和小数点的位置。

    现在,这是一个简化的示例。浮点数存储 二进制 值而不是十进制值。 32-bit IEEE 754 float 有 23 个“有效位”(加上始终假定为 1 的第一个)的空间,对应于大约 7-8 个十进制数字。

     1234567001.00 (dec) =
    
     1001001100101011111111101011001.00 (bin)  gets rounded to
    
     1001001100101011111111110000000.00 =
      |    23 bits           |
    
     1234567040.00 (dec)
    

    这正是 C 产生的:

    void main() {
        float a = 1234567001;
        printf("%f", a);      // outputs 1234567040
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2010-12-19
      • 2021-09-16
      • 2011-02-23
      • 1970-01-01
      • 2020-02-03
      • 2011-08-26
      相关资源
      最近更新 更多