浮点文字中有效十进制数字的最小位数是多少,以尽可能正确地表示该值?
What is the minimum number of significant decimal digits in a floating point literal to represent the value as correct as possible?
例如,使用 IEEE-754 32 位二进制浮点数,我们来表示 1 / 3
的值。它不能完全完成,但 0x3eaaaaab
产生最接近 1 / 3
的值。您可能希望以十进制形式写入值,并让编译器将十进制文字转换为二进制浮点数。
0.333333f -> 0x3eaaaa9f (0.333332986)
0.3333333f -> 0x3eaaaaaa (0.333333313)
0.33333333f -> 0x3eaaaaab (0.333333343)
0.333333333f -> 0x3eaaaaab (0.333333343)
可以看到8位(有效的)十进制数字就足以表示尽可能正确的值(最接近实际值)。
我用 π 和 e(自然对数的底数)进行了测试,两者都需要 8 位小数才能最正确。
3.14159f -> 0x40490fd0 (3.14159012)
3.141593f -> 0x40490fdc (3.14159298)
3.1415927f -> 0x40490fdb (3.14159274)
3.14159265f -> 0x40490fdb (3.14159274)
2.71828f -> 0x402df84d (2.71828008)
2.718282f -> 0x402df855 (2.71828198)
2.7182818f -> 0x402df854 (2.71828175)
2.71828183f -> 0x402df854 (2.71828175)
但是,√2
似乎需要 9 位数字。
1.41421f -> 0x3fb504d5 (1.41420996)
1.414214f -> 0x3fb504f7 (1.41421402)
1.4142136f -> 0x3fb504f4 (1.41421366)
1.41421356f -> 0x3fb504f3 (1.41421354)
1.414213562f -> 0x3fb504f3 (1.41421354)
https://godbolt.org/z/W5vEcs695
从这些结果来看,具有 9 位有效数字的十进制浮点文字足以产生最正确的 32 位二进制浮点值可能是正确的,实际上 12~15 位数字就可以了确定 space 是否用于存储额外的数字并不重要。
但我对它背后的数学很感兴趣。在这种情况下,如何确定 9 位数字就足够了? double
甚至任意精度,有没有简单的公式可以推导出所需的位数?
当前的答案和评论中的链接确认 9
数字足以满足 大多数 的情况,但我发现了一个反例 9
位数不够。事实上,十进制格式的无限精度需要始终正确转换(四舍五入到最接近的)某种二进制浮点格式(IEEE-754 binary32 floats 供讨论)。
8388609.499
用9
位有效小数表示为8388609.50
。此数字转换为 float
后的值为 8388610
。另一方面,用10
或更多位表示的数字将始终保留原始值,并且此数字转换为float
具有值8388609
。
您可以看到 8388609.499
需要多于 9
位才能最准确地转换为 float
。有无限多个这样的数字,非常接近二进制浮点格式中两个可表示值的半点。
我认为您正在寻找 *_DECIMAL_DIG
常量。 C 标准提供了关于如何计算它们的小解释和公式(N2176 C17 草案):
5.2.4.2.2 Characteristics of floating types <float.h>
The values given in the following list shall be replaced by constant expressions with implementation-defined values that are greater or equal in magnitude (absolute value) to those shown, with the
same sign:
...
number of decimal digits, n, such that any floating-point number with p radix b digits can be rounded to a floating-point number with n decimal digits and back again without change to the value,
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
使用 IEEE-754 32 位浮点数 b = FLT_RADIX = 2
和 p = FLT_MANT_DIG = 24
,结果为 FLT_DECIMAL_DIG = ⌈1 + 24 log10 2⌉ = 9
。 (⌈x⌉=ceil(x)
) 是上限函数:向上舍入结果)
What is the minimum number of significant decimal digits in a floating point literal to represent the value as correct as possible?
C 标准无法保证 floating-point 文字中的任何小数位数都将产生最接近 floating-point 格式实际可表示的值。在讨论 floating-point 文字时,C 2018 6.4.4.2 3 说:
… For decimal floating constants, … the result is either the nearest representable value, or the larger or smaller representable value immediately adjacent to the nearest representable value, chosen in an implementation-defined manner…
为了质量,C 实现应该正确地将 floating-point 文字四舍五入到最接近的可表示值,并与偶数位较低的选项保持一致。在这种情况下,在 <float.h>
中定义的 FLT_DECIMAL_DIG
、DBL_DECIMAL_DIG
和 LDBL_DECIMAL_DIG
值提供了始终足以唯一标识可表示值的位数。
How can one be sure that 9 digits is enough in this case?
您需要在编译器文档中声明这方面的效果,例如声明它为 floating-point 文字提供正确的舍入并且它使用 IEEE-754 binary32(a.k.a。“单精度” ) 对于 float
(或其他一些只需要九个有效数字来唯一标识所有可表示值的格式)。
What about double or even arbitrary precision, is there a simple formula to derive the number of digits needed?
C 标准表示上面的常数计算为 p log10 b 如果b 是十的幂和 ceil(1 + p log10 b ) 否则,其中 p 是 floating-point 格式中的位数,而 b 是使用的基数格式。这些总是足够的,但后者并不总是必要的。如果指数范围是无限的,后者提供所需的位数;从某种意义上说,它的“1+”涵盖了 b 的幂如何与 10 的幂相互作用的所有可能余量。但是任何 floating-point 格式都有一个有限的指数范围,并且对于某些指数范围的选择, ceil(p log10 b) 就足够了,而不是 ceil(1 + p log10 b).这没有简单的公式。它不会出现在标准 IEEE-754 格式中,在实践中可以忽略。
What about double or even arbitrary precision, is there a simple formula to derive the number of digits needed?>
来自 C17 § 5.2.4.2.2 11 FLT_DECIMAL_DIG, DBL_DECIMAL_DIG, LDBL_DECIMAL_DIG
number of decimal digits, n, such that any floating-point number with p radix b digits can be rounded to a floating-point number with n decimal digits and back again without change to the value,
pmax log10 b:如果b
是10的幂
1 + pmax log10 b:否则
But I'm interested in the math behind it. How can one be sure that 9 digits is enough in this case?
二进制浮点数的每个范围如 [1.0 ... 2.0), [128.0 ... 256.0), [0.125 ... 0.5) 包含 2p - 1值均匀分布。例如float
,p = 24。
十进制文本的每个范围具有 n
指数表示法中的有效数字,例如 [1.0 ... 9.999...), [100.0f ... 999.999...), [0.001 ... 0.00999...) 包含 10n - 1 个均匀分布的值。
示例:常见 float
:
当 p
为 24 和 224 组合时,n
必须至少 8 才能形成 16,777,216 种组合以明确 round-trip float
将十进制文本转为 float
。由于上面两个小数范围的 end-points 可能很好地存在于 224 的集合中,因此较大的小数值间隔得更远。这需要一个 +1 小数位。
示例:
考虑 2 个相邻的 float
值
10.000009_5367431640625
10.000010_49041748046875
两者都转换为 8 位有效数字的十进制文本 "10.000010"
。 8个不够。
9 总是足够的,因为我们不需要超过 167,772,160 来区分 16,777,216 个 float
值。
OP 还询问 8388609.499
。 (为简单起见,我们只考虑 float
。)
该值几乎 half-way 介于 2 float
个值之间。
8388609.0f // Nearest lower float value
8388609.499 // OP's constant as code
8388610.0f // Nearest upper float value
OP 报告:“您可以看到 8388609.499 需要超过 9 位数字才能最准确地转换为浮点数。”
然后让我们回顾一下标题“浮点数中有效小数位数的最小位数是多少*1来表示值 尽可能正确?"
这个新问题部分强调所讨论的 value 是源代码 8388609.499
的值,而不是它在发出的代码中变成的浮点常量:8388608.0f
.
如果我们将值视为浮点常量的值,则最多只需要9位有效的小数位定义 浮点常量 8388608.0f
。 8388608.49,源代码就够了。
但是要根据一些数字获得最接近的 浮点常量 是的,确实需要很多数字。
考虑典型的最小值 float
,FLT_TRUE_MIN
具有精确的十进制值:
0.00000000000000000000000000000000000000000000140129846432481707092372958328991613128026194187651577175706828388979108268586060148663818836212158203125
那个和 0.0 之间的一半是 0.000..(~39 个零)..0007006..(~100 个数字)..15625.
如果最后一位数字是 6 或 4,最接近的 float
将分别是 FLT_TRUE_MIN
或 0.0f
。所以现在我们有一个情况,在 2 个可能的 float
.
之间“需要”109 个有效数字到 select
为了避免我们讨论 cliffs of insanity,IEEE-758 已经解决了这个问题。
翻译(编译器)必须检查以符合该规范(不一定是 C 规范)的有效十进制数字的数量要有限得多,即使额外的数字可以转换为另一个 FP 值。
IIRC,生效FLT_DECIMAL_DIG + 3
。因此,对于一个常见的 float
,可以检查少至 9 + 3 位有效的小数位。
[编辑]
*1 C 没有定义:浮点字面值,但是定义了浮点常量[=126] =],因此使用了该术语。
例如,使用 IEEE-754 32 位二进制浮点数,我们来表示 1 / 3
的值。它不能完全完成,但 0x3eaaaaab
产生最接近 1 / 3
的值。您可能希望以十进制形式写入值,并让编译器将十进制文字转换为二进制浮点数。
0.333333f -> 0x3eaaaa9f (0.333332986)
0.3333333f -> 0x3eaaaaaa (0.333333313)
0.33333333f -> 0x3eaaaaab (0.333333343)
0.333333333f -> 0x3eaaaaab (0.333333343)
可以看到8位(有效的)十进制数字就足以表示尽可能正确的值(最接近实际值)。
我用 π 和 e(自然对数的底数)进行了测试,两者都需要 8 位小数才能最正确。
3.14159f -> 0x40490fd0 (3.14159012)
3.141593f -> 0x40490fdc (3.14159298)
3.1415927f -> 0x40490fdb (3.14159274)
3.14159265f -> 0x40490fdb (3.14159274)
2.71828f -> 0x402df84d (2.71828008)
2.718282f -> 0x402df855 (2.71828198)
2.7182818f -> 0x402df854 (2.71828175)
2.71828183f -> 0x402df854 (2.71828175)
但是,√2
似乎需要 9 位数字。
1.41421f -> 0x3fb504d5 (1.41420996)
1.414214f -> 0x3fb504f7 (1.41421402)
1.4142136f -> 0x3fb504f4 (1.41421366)
1.41421356f -> 0x3fb504f3 (1.41421354)
1.414213562f -> 0x3fb504f3 (1.41421354)
https://godbolt.org/z/W5vEcs695
从这些结果来看,具有 9 位有效数字的十进制浮点文字足以产生最正确的 32 位二进制浮点值可能是正确的,实际上 12~15 位数字就可以了确定 space 是否用于存储额外的数字并不重要。
但我对它背后的数学很感兴趣。在这种情况下,如何确定 9 位数字就足够了? double
甚至任意精度,有没有简单的公式可以推导出所需的位数?
当前的答案和评论中的链接确认 9
数字足以满足 大多数 的情况,但我发现了一个反例 9
位数不够。事实上,十进制格式的无限精度需要始终正确转换(四舍五入到最接近的)某种二进制浮点格式(IEEE-754 binary32 floats 供讨论)。
8388609.499
用9
位有效小数表示为8388609.50
。此数字转换为 float
后的值为 8388610
。另一方面,用10
或更多位表示的数字将始终保留原始值,并且此数字转换为float
具有值8388609
。
您可以看到 8388609.499
需要多于 9
位才能最准确地转换为 float
。有无限多个这样的数字,非常接近二进制浮点格式中两个可表示值的半点。
我认为您正在寻找 *_DECIMAL_DIG
常量。 C 标准提供了关于如何计算它们的小解释和公式(N2176 C17 草案):
5.2.4.2.2 Characteristics of floating types <float.h>
The values given in the following list shall be replaced by constant expressions with implementation-defined values that are greater or equal in magnitude (absolute value) to those shown, with the same sign:
...
number of decimal digits, n, such that any floating-point number with p radix b digits can be rounded to a floating-point number with n decimal digits and back again without change to the value,
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
使用 IEEE-754 32 位浮点数 b = FLT_RADIX = 2
和 p = FLT_MANT_DIG = 24
,结果为 FLT_DECIMAL_DIG = ⌈1 + 24 log10 2⌉ = 9
。 (⌈x⌉=ceil(x)
) 是上限函数:向上舍入结果)
What is the minimum number of significant decimal digits in a floating point literal to represent the value as correct as possible?
C 标准无法保证 floating-point 文字中的任何小数位数都将产生最接近 floating-point 格式实际可表示的值。在讨论 floating-point 文字时,C 2018 6.4.4.2 3 说:
… For decimal floating constants, … the result is either the nearest representable value, or the larger or smaller representable value immediately adjacent to the nearest representable value, chosen in an implementation-defined manner…
为了质量,C 实现应该正确地将 floating-point 文字四舍五入到最接近的可表示值,并与偶数位较低的选项保持一致。在这种情况下,在 <float.h>
中定义的 FLT_DECIMAL_DIG
、DBL_DECIMAL_DIG
和 LDBL_DECIMAL_DIG
值提供了始终足以唯一标识可表示值的位数。
How can one be sure that 9 digits is enough in this case?
您需要在编译器文档中声明这方面的效果,例如声明它为 floating-point 文字提供正确的舍入并且它使用 IEEE-754 binary32(a.k.a。“单精度” ) 对于 float
(或其他一些只需要九个有效数字来唯一标识所有可表示值的格式)。
What about double or even arbitrary precision, is there a simple formula to derive the number of digits needed?
C 标准表示上面的常数计算为 p log10 b 如果b 是十的幂和 ceil(1 + p log10 b ) 否则,其中 p 是 floating-point 格式中的位数,而 b 是使用的基数格式。这些总是足够的,但后者并不总是必要的。如果指数范围是无限的,后者提供所需的位数;从某种意义上说,它的“1+”涵盖了 b 的幂如何与 10 的幂相互作用的所有可能余量。但是任何 floating-point 格式都有一个有限的指数范围,并且对于某些指数范围的选择, ceil(p log10 b) 就足够了,而不是 ceil(1 + p log10 b).这没有简单的公式。它不会出现在标准 IEEE-754 格式中,在实践中可以忽略。
What about double or even arbitrary precision, is there a simple formula to derive the number of digits needed?>
来自 C17 § 5.2.4.2.2 11 FLT_DECIMAL_DIG, DBL_DECIMAL_DIG, LDBL_DECIMAL_DIG
number of decimal digits, n, such that any floating-point number with p radix b digits can be rounded to a floating-point number with n decimal digits and back again without change to the value,
pmax log10 b:如果b
是10的幂
1 + pmax log10 b:否则
But I'm interested in the math behind it. How can one be sure that 9 digits is enough in this case?
二进制浮点数的每个范围如 [1.0 ... 2.0), [128.0 ... 256.0), [0.125 ... 0.5) 包含 2p - 1值均匀分布。例如float
,p = 24。
十进制文本的每个范围具有 n
指数表示法中的有效数字,例如 [1.0 ... 9.999...), [100.0f ... 999.999...), [0.001 ... 0.00999...) 包含 10n - 1 个均匀分布的值。
示例:常见 float
:
当 p
为 24 和 224 组合时,n
必须至少 8 才能形成 16,777,216 种组合以明确 round-trip float
将十进制文本转为 float
。由于上面两个小数范围的 end-points 可能很好地存在于 224 的集合中,因此较大的小数值间隔得更远。这需要一个 +1 小数位。
示例:
考虑 2 个相邻的 float
值
10.000009_5367431640625
10.000010_49041748046875
两者都转换为 8 位有效数字的十进制文本 "10.000010"
。 8个不够。
9 总是足够的,因为我们不需要超过 167,772,160 来区分 16,777,216 个 float
值。
OP 还询问 8388609.499
。 (为简单起见,我们只考虑 float
。)
该值几乎 half-way 介于 2 float
个值之间。
8388609.0f // Nearest lower float value
8388609.499 // OP's constant as code
8388610.0f // Nearest upper float value
OP 报告:“您可以看到 8388609.499 需要超过 9 位数字才能最准确地转换为浮点数。”
然后让我们回顾一下标题“浮点数中有效小数位数的最小位数是多少*1来表示值 尽可能正确?"
这个新问题部分强调所讨论的 value 是源代码 8388609.499
的值,而不是它在发出的代码中变成的浮点常量:8388608.0f
.
如果我们将值视为浮点常量的值,则最多只需要9位有效的小数位定义 浮点常量 8388608.0f
。 8388608.49,源代码就够了。
但是要根据一些数字获得最接近的 浮点常量 是的,确实需要很多数字。
考虑典型的最小值 float
,FLT_TRUE_MIN
具有精确的十进制值:
0.00000000000000000000000000000000000000000000140129846432481707092372958328991613128026194187651577175706828388979108268586060148663818836212158203125
那个和 0.0 之间的一半是 0.000..(~39 个零)..0007006..(~100 个数字)..15625.
如果最后一位数字是 6 或 4,最接近的 float
将分别是 FLT_TRUE_MIN
或 0.0f
。所以现在我们有一个情况,在 2 个可能的 float
.
为了避免我们讨论 cliffs of insanity,IEEE-758 已经解决了这个问题。
翻译(编译器)必须检查以符合该规范(不一定是 C 规范)的有效十进制数字的数量要有限得多,即使额外的数字可以转换为另一个 FP 值。
IIRC,生效FLT_DECIMAL_DIG + 3
。因此,对于一个常见的 float
,可以检查少至 9 + 3 位有效的小数位。
[编辑]
*1 C 没有定义:浮点字面值,但是定义了浮点常量[=126] =],因此使用了该术语。