C语言中FLT_DIG、DBL_DIG、LDBL_DIG是如何确定的

How are FLT_DIG, DBL_DIG, and LDBL_DIG determined in C

FLT_DIG、DBL_DIG、LDBL_DIG分别是float、double、long double类型可以准确表示的小数位数。

#include <stdio.h>
#include <float.h>

int main(void)
{
  printf("%d, %d, %d\n", FLT_DIG, DBL_DIG, LDBL_DIG);
  return 0;
}

打印 61518。该标准在第 5.2.4.2.2 节中给出了准确的公式——例如对于浮点数,p = 24 和 b = 2:

但是我不清楚上面的公式("otherwise")是怎么推导出来的。有人可以解释一下吗?

以下是我的推理,没有回答问题。考虑在有效位(IEEE-754 标准)中有 23 位的浮点类型。可以准确表示的最大二进制整数为:

  100...00 (25 digits total, because we have an implicit 1)
  = 2^24
  = 10^(24*log(2)) 

因此#个十进制数字:

= floor(24*log(2)) = 7

而不是标准规定的 floor(23 * log(2)) = 6

以下是我的看法。免责声明:我只是一个程序员,不是数学家,更不是数论家,你问的问题对他们来说形成了(我相信)一个中心定理。

每个人都知道以 10 为底数:两位数字给你 102 或 100 个值,三位数字给你 103 或 1000 个值,等等

每个程序员都知道以 10 为基数:八位给你 28 或 256 个值,十六位(两个字节)给你 216 或 65536 个值等

那么问题来了,一个十进制数有多少位?

嗯,23是8,所以多了3位。而24是16,所以还不到4位。

你知道对数吧? (您询问的公式中有一个,所以我希望您至少对它们有所了解。)对数是求幂的倒数。如果102是100,那么log10100就是2。如果28是256,那么log2 256 是 8.

所以一个十进制数的二进制位数是log210,结果大约是3.322。 (看,我是对的:大于 3,小于 4。)

我们也可以走另一条路。如果216是65536,16位对应多少十进制数?很明显是5左右:我们需要5个数字来写65536。但实际上它必须比5少一点,因为用5个十进制数字我们最多可以表示大约99999个不同的值,这超过了16位。

事实上,根据我们之前的结果,十进制数字中有 3.322 个二进制位,我们需要 16 ÷ 3.322 ≊ 4.8 位十进制数字来准确表示 16 位。

最后,让我们看看浮点数。根据维基百科,IEEE 754 single-precision floating-point format(通常是 C float)具有 24 位的有效值(又名 "mantissa")。使用我们方便的换算系数,这相当于 24 ÷ 3.322 ≊ 7.2 十进制数字。 (实际上,由于 IEEE-754 中的复杂因素,例如非规范化数字和隐式 1 位,它比这更复杂,但现在 7.2 位数字可以作为答案。)

我有点误导你了,因为我一直在使用 log210 ≊ 的转换因子; 3.322 在二进制位和十进制数字之间来回切换,而你引用的公式有 log10 b (我们 b 大概是 2)。另外,看:它们乘以 log10 b,而我一直在除以 log210。惊喜,惊喜:log210 == 1 / (log10 2)。 (我确定有一个很好的证明,但这个答案太长了。)

How are FLT_DIG, DBL_DIG, and LDBL_DIG determined (?)

大致,用p个二进制数,可以编码p*(log102)个十进制数。每个二进制数字都贡献了大约 .3 个十进制数字。

将浮点值和数字回忆为具有 n 表示数字和指数的十进制文本,在更大的 对数 [=53] 中呈 线性分布 =]分布.

下面的 -1 来自最坏情况下的对齐问题,其中十进制值的分布相对于二进制值最为密集。如果 float 基数为 10,则没有 -1,因为分布对齐。

The below is the reasoning I followed which does not answer the question. ...

根据 here 中的第 6 条,OP 的推理失败了。十进制值与二进制值的对齐并不总是 "work".

A float 作为 binary32 示例。

  1. 在 [233 或 8,589,934,592 ... 234 或 17,179,869,184) 范围内,再次,2 23 (8,388,608) 个值是 线性 编码的:彼此相距 1024.0。在子范围 [9,000,000,000 和 10,000,000,000) 中,大约有 976,562 个不同的值。

  2. 作为文本,范围[9,000,000*103和10,000,000*103),使用1个线索digit 和 6 trailing ones,有 1,000,000 个不同的值。根据 #1,在同一范围内,不同的 float 值少于 1,000,000 个。因此,一些十进制文本值将转换为相同的 float在此范围内,我们可以使用 6 个而不是 7 个数字 进行独特的转换。