繁体   English   中英

C 浮点数中的精度

[英]Precision in C floats

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

“小数点后 6 位数字”是无稽之谈,你的例子很好地证明了这一点。

float数据类型的精确规范。

float的精度为24位。 根据在线消息来源,有 23 位表示二进制小数点后的小数,另外还有一个“隐式前导位”。 这总共给出了 24 个有效位。

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

24 * 日志(2)/日志(10)= 7.22

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

你是对的,当数字较大时,小数点后的位数会改变 - 但如果我们谈论精度,当数字较大时,有效数字的数量不会改变。 然而,十进制数的答案并不简单:


现在大多数系统都使用IEE 浮点格式来表示 C 中的数字。但是,如果您正在处理一些不寻常的事情,那么值得检查一下。 单精度 IEE float由三部分组成:

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

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


有多少有效数字?

如果您使用的是 IEE-754 数字,“有多少有效数字”可能不是一个简单的思考方式,因为精度是以二进制有效数字而不是十进制来衡量的 float的小数部分只有 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 之间,只能表示偶数,因为任何奇数的最后一位都丢失了。

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

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

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

因此,可以用这种表示近似的最大十进制数字数是: log 10 (2 24 ) = 7.22 这近似于七个有效的十进制数字,以及一个从 2 -126到 2 127的指数。

请注意,指数是单独测量的。 这就像您使用普通的科学记数法一样,例如“一个人重 72.3 公斤 = 7.23×10 4克”。 注意这里有三位有效数字,代表数字只精确到100克以内。 但也有一个完全不同的指数 你可以有一个非常大的指数,但有效数字很少,比如“太阳的重量是 1.99×10 33克”。 大数字,几位数。

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

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

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

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

现在,这是一个简化的示例。 浮点数存储二进制值而不是十进制值。 一个32 位的 IEEE 754 浮点数有 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
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM