当前位置: 首页 > 知识库问答 >
问题:

浮点文字中有效十进制数字的最小数量是多少,以尽可能正确地表示值?

慕容渊
2023-03-14

例如,使用 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位数字肯定可以工作。

但我对它背后的数学很感兴趣。在这种情况下,如何确定9位数就足够了呢?< code>double甚至任意精度呢,有没有简单的公式推导出需要的位数?

目前的答案和评论中的链接证实了< code>9位对于大多数情况来说是足够的,但是我发现了一个反例,其中< code>9位是不够的。事实上,十进制格式的无限精度需要始终正确地转换(四舍五入到最接近的值)为某种二进制浮点格式(IEEE-754二进制32浮点用于讨论)。

用< code>9位有效小数表示的< code>8388609.499是< code>8388609.50。转换为< code>float的这个数字的值为< code>8388610。另一方面,用< code>10或更多数字表示的数字将始终保持原始值,并且这个数字转换为< code>float后具有值< code>8388609。

您可以看到8388609.499需要超过9位才能最准确地转换为浮点数。有无限多这样的数字,它们以二进制浮点数格式放置在非常接近两个可表示值的半点的位置。

共有3个答案

呼延明朗
2023-03-14

浮点文字中有效十进制数字的最小数量是多少,以尽可能正确地表示值?

C标准不能保证浮点文字中任何数量的十进制数字都会产生浮点格式中实际可表示的最近值。在讨论浮点文字时,C 20186.4.4.23说:

…对于十进制浮点数,…结果要么是最近的可表示值,要么是紧邻最近可表示值的较大或较小可表示值(以实现定义的方式选择)…

为了提高质量,C实现应该正确地将浮点字面值四舍五入到最接近的可表示值,并使用偶数低位进行匹配。在这种情况下,中定义的FLT_DECIMAL_DIG

在这种情况下,如何确保9位数就足够了?

您需要在编译器文档中提供与此效果的语句,例如,它为浮点文本提供正确的舍入,并且它使用 IEEE-754 binary32(又名“单精度”)作为浮点数(或一些其他格式,只需要九位有效数字来唯一标识所有可表示的值)。

双精度甚至任意精度呢,有没有简单的公式推导出需要的位数?

C标准表明,如果b是10的幂,则上述常数计算为p log10b,否则,p是浮点格式中的位数,b是格式中使用的基数。这些总是足够的,但后者并不总是必要的。后者提供了指数范围无界时所需的位数;在某种意义上,它的“1”涵盖了b的幂与10的幂如何相互作用的所有可能的余量。但是任何浮点格式都有一个有限的指数范围,对于指数范围的某些选择,ceil(p log10b)就足够了,而不是ceil(1 p log10b)。对此没有简单的公式。标准IEEE-754格式不会出现这种情况,在实践中可以忽略。

金理
2023-03-14

双精度甚至任意精度呢,有没有简单的公式推导出需要的位数?

从 C17 § 5.2.4.2.2 11 FLT_DECIMAL_DIG, DBL_DECIMAL_DIG, LDBL_DECIMAL_DIG

十进制数 n,使得任何具有 p 基数 b 位的浮点数都可以舍入为具有 n 个十进制数字的浮点数,然后再返回,而无需更改值,

p最大对数10 b:如果 b 是 10 的幂
1 p最大对数10 b:否则

但我对它背后的数学很感兴趣。在这种情况下,如何确定9位数字就足够了?

二进制浮点的每个范围,如[1.0…2.0)、[128.0…256.0)、[0.125…0.5),都包含均匀分布的2p-1值。例如,使用float,p=24。

在类似[1.0]的指数符号中,十进制文本的每个十进制范围具有< code>n个有效数字...9.999...),[100.0f...999.999...), [0.001 ...0.00999...)包含10n - 1个均匀分布的值。

示例:常见的浮点数
p为24且有2个24组合时,n必须至少8个才能形成16,777,216个组合,以清楚地往返浮点数浮点数的十进制文本。由于上述两个十进制范围的endpoint可能存在于224的集合中,因此较大的十进制值间隔更远。这需要一个1位十进制数字。

例:

考虑两个相邻的< code>float值

10.000009_5367431640625
10.000010_49041748046875

两者都转换为8位有效数字的十进制文本< code >“10.000010”。8是不够的。

9总是足够的,因为我们不需要超过167772160来区分16777216float值。

OP还询问有关8388609.499的信息。(为了简单起见,我们只考虑浮动。

该值几乎介于2float值之间。

8388609.0f  // Nearest lower float value
8388609.499 // OP's constant as code
8388610.0f  // Nearest upper float value

OP报告:“您可以看到8388609.499需要超过9位数才能最准确地转换为浮点数。”

让我们回顾一下标题“浮点字面*1中有效十进制数字的最小数量是多少,以尽可能正确地表示该值?

这个新的问题部分强调,所讨论的值是源代码8388609.499的值,而不是它在发出的代码中变成的浮点常量:8388608.0f

如果我们认为该值是浮点常量的值,则最多只需要9个有效的十进制数字即可定义浮点常量8388608.0f.8388608.49,因为源代码就足够了。

但是,要根据某个数字作为代码获得最接近的浮点常量,yes确实需要很多位数。

考虑典型的最小浮点FLT_TRUE_MINwith the exact decimal value:

0.00000000000000000000000000000000000000000000140129846432481707092372958328991613128026194187651577175706828388979108268586060148663818836212158203125

在这和0.0之间的一半是0.000.(多39个零)..0007006..(多100个数字)..15625。

如果最后一个数字是6或4,最接近< code >浮点数将分别是< code > FLT _真_分或< code>0.0f。因此,现在我们有一个案例,其中“需要”109个有效数字来在两个可能的< code>float之间进行选择。

为了放弃我们越过疯狂的悬崖,IEEE-758已经解决了这个问题。

翻译(编译器)必须检查以符合该规范(不一定是C规范)的有效十进制数字的数量要有限得多,即使额外的数字可以转换为另一个FP值。

IIRC,它生效FLT_DECIMAL_DIG 3。因此,对于常见的float,只需检查9到3个有效十进制数字。

[编辑]

正确的舍入只能保证所需的十进制位数加上3,以支持最大的二进制格式。

*1C没有定义:浮点文字,但定义了浮点常量,因此使用了该术语。

吕天逸
2023-03-14

我认为您正在寻找*_DECIMAL_DIG常量。C标准提供了关于如何计算它们的小解释和公式(N2176 C17草案):

以下列表中给出的值应替换为常量表达式,其执行定义的值在量级(绝对值)上大于或等于所示值,符号相同:

...

> < li>

十进制位数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

使用 IEEE-754 32 位浮点数 b = FLT_RADIX = 2p = FLT_MANT_DIG = 24,则结果为 FLT_DECIMAL_DIG = ⌈1 24 log10 2⌉ = 9。(⌈x⌉=天花板(x))是上限函数:结果向上舍入)

 类似资料:
  • 我在这篇维基百科文章中找到了以下关于单精度浮点数的陈述https://en.wikipedia.org/wiki/Single-precision_floating-point_format: 如果将IEEE 754单精度数字转换为具有至少9位有效数字的十进制字符串,然后转换回单精度表示,则最终结果必须与原始数字匹配。 我曾试图找到实际需要9位有效十进制数字的单精度浮点数示例,这些数字只有8位有效

  • 在浮点数字类型的C#参考中,可以看到 的精度为6到9位 的精度为15到17位 的精度为28到29位 在这种情况下,意味着什么,尤其是,如何成为一个范围?由于指数和尾数的位数是固定的,

  • 问题内容: 浮点数是否具有32个二进制数字,而双精度数是否具有64个二进制数字?该文档太难理解了。 所有位都转换为有效数字吗?还是小数点的位置占用了一些位? 问题答案: float:32位(4个字节),其中23位用于尾数(约7个十进制数字)。指数使用8位,因此浮点数可以使用这8位将小数点“移动”到右边或左边。这样做避免了像0.0000003(3×10 -7)或3000000(3×10 7)那样在尾

  • 问题内容: 首先, 我需要使用正则表达式来匹配或或(仅是国家编号)。我需要的用户能够输入一个并没有什么之后。似乎无法正确解决。 我发现所有正则表达式都匹配 所有 十进制数字,即 像这个正则表达式 问题是,我需要一个正则表达式,因此输入只能是带/不带小数点的数字。 但是要抓住的是它也需要匹配 因此,用户可以在文本字段中输入小数。所以基本上我需要用正则表达式来匹配 到目前为止,我的模式就是上面的模式。

  • 问题内容: 首先, 我需要使用正则表达式来匹配或或(仅是国家编号)。我需要的用户能够输入一个并没有什么之后。似乎无法正确解决。 我发现所有正则表达式都匹配 所有 十进制数字,即 像这个正则表达式 问题是,我需要一个正则表达式,因此输入只能是带/不带小数点的数字。 但是要抓住的是它也需要匹配 因此,用户可以在文本字段中输入小数。所以基本上我需要用正则表达式来匹配 到目前为止,我的模式就是上面的模式。

  • 问题内容: python中最小和最大的值是什么? 问题答案: 看到这篇文章。 帖子的相关部分: