浮点字面的最小小数位数的最低数量是多少,以表示尽可能正确的值?
例如,使用IEEE-754 32位二进制浮点,让我们表示1/3 < / code>的值。它不能准确地完成,但是
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位数足够? double
甚至任意精度呢,是否有一个简单的公式来得出所需的数字数?
当前答案和评论中的链接确认9
数字足以满足最多案例,但是我找到了一个反例,其中9
digits还不够。实际上,必须以十进制格式的无限精度正确转换(最接近的)到某些二进制浮点格式(IEEE-754 binary32 floats进行讨论)。
8388609.499
用9
代表大量小数是8388609.50
。此数字转换为float
具有8388610
的值。另一方面,用10
或更多数字表示的数字始终保留原始值,并且此数字转换为float
具有值8388609
。
您可以看到8388609.499
需要超过9
数字最准确地转换为float
。有许多这样的数字,在二进制浮点格式中非常接近两个代表值的半点。
For example, using IEEE-754 32-bit binary floating points, let's represent the value of 1 / 3
. It cannot be done exactly, but 0x3eaaaaab
produces the closest value to 1 / 3
. You might want to write the value in decimal, and let the compiler to convert the decimal literal to a binary floating point number.
0.333333f -> 0x3eaaaa9f (0.333332986)
0.3333333f -> 0x3eaaaaaa (0.333333313)
0.33333333f -> 0x3eaaaaab (0.333333343)
0.333333333f -> 0x3eaaaaab (0.333333343)
You can see that 8 (significant) decimal digits is enough to represent the value as correct as possible (closest to the actual value).
I tested with π and e (base of the natural log), and both needed 8 decimal digits for the correctest.
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)
However, √2
appears to need 9 digits.
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
Looking at these results, it's probably right that a decimal floating-point literal with 9 significant digits is sufficient to produce a most correct 32-bit binary floating point value, and in practice something like 12~15 digits would work for sure if space for storing the extra digits doesn't matter.
But I'm interested in the math behind it. How can one be sure that 9 digits is enough in this case? What about double
or even arbitrary precision, is there a simple formula to derive the number of digits needed?
The current answers and the links in the comments confirm that 9
digits is enough for most cases, but I've found a counterexample where 9
digits is not enough. In fact, infinite precision in the decimal format is required to be always correctly converted (rounded to the closest) to some binary floating point format (IEEE-754 binary32 floats for the discussion).
8388609.499
represented with 9
significant decimal digits is 8388609.50
. This number converted to float
has the value of 8388610
. On the other hand, the number represented with 10
or more digits will always preserve the original value, and this number converted to float
has the value 8388609
.
You can see 8388609.499
needs more than 9
digits to be most accurately converted to float
. There are infinitely many such numbers, placed very close to the half point of two representable values in the binary float format.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
我认为您正在寻找
*_ DECIMAL_DIG
常数。 C标准提供了有关如何计算它们的小解释和公式(N2176 C17草案):使用IEEE-754 32位float
b = flt_radix = 2
和p = flt_mant_dig = 24 ,结果为
flt_decimal_dig =⌈1 + 24 log102⌉= 9
。 (⌈X⌉= ceil(x)
)是天花板功能:圆结果)I think you are looking for
*_DECIMAL_DIG
constants. C standard provides small explanation and formula on how they are calculated (N2176 C17 draft):With IEEE-754 32-bit float
b = FLT_RADIX = 2
andp = FLT_MANT_DIG = 24
, result isFLT_DECIMAL_DIG = ⌈1 + 24 log10 2⌉ = 9
. (⌈x⌉=ceil(x)
) is ceiling function: round result up)来自C17§5.2.4.2.211
flt_decimal_dig,dbl_decimal_dig,ldbl_decimal_dig
pmax log 10 b:如果
b
是一个功率为101 + p max log 10 b:否则
[1.0 ... 2.0),[128.0 ... 256.0),[0.125 ... 0.5)的每个二进制浮点的范围均包含2 p -1 值均匀分布。例如,使用
float
,p = 24。十年的小数文本的每个范围,带有
n
指数符号中的重要数字,例如[1.0 ... 9.999 ...),[ 100.0f ... 999.999 ...),[0.001 ... 0.00999 ...)包含10 n -1 值均匀分布。示例:common
float
:当
p
是24 24 组合时,n
必须在 最少 8中,才能形成16,777,216的组合-tripfloat
将小数为float
的文本。由于上面的两个小数范围的端点可能很大程度存在于2 24 的集合中,因此较大的小数值远距离分开。这需要+1小数位数。示例:
考虑2相邻
float
值两个转换为8个重要数字十进制文本
“ 10.000010”
。 8还不够。9总是足够的,因为我们不需要超过167,772,160来区分16,777,216
float
值。OP还询问
8388609.499
。 (为简单起见,让我们仅考虑float
。)该值几乎是2
float
值之间的一半。OP报告:“您可以看到8388609.499需要9位以上的数字才能最准确地转换为浮点。”
并让我们查看标题“浮点字面*1 中的最小小数位数的最小数量是多少,以表示 value 尽可能正确?”
这个新问题部分强调,有问题的 value 是源代码
8388609.499
的值,而不是浮点常数,它在发射的代码中变为:8388608.0f << /代码>。
如果我们将 value 视为浮点数常数的值>
8388608.0F
。 8388608.49,作为源代码就足够了。但是,要根据某个数字获得最接近的浮点常数,因为代码是的,确实可以花很多数字。
考虑典型的最小
float
, /code> 确切的小数为:一半和0.0之间的十进制值为0.000 ..(〜39个零).. 0007006 ..(〜100多数数字).. 15625。
最后一个数字是6或4,最接近的
float
将分别为flt_true_min
或0.0F
。因此,现在我们有一个“需要” 109个重要数字来选择2个可能的float
之间的情况。放弃我们浏览疯狂的悬崖,IEEE-758已经解决了这一问题。
即使额外的数字可以转换为另一个fp值,即使符合该规格的重大十进制数字(编译器)必须符合该规格(不一定是C规格)的数量。
IIRC,它实际上是
flt_decimal_dig + 3
。因此,对于常见的float
,可以检查到9 + 3个重要的十进制数字。[edit]
正确的四舍五入只能保证所需的十进制数量的数量支持的二进制格式。
*1 c不定义:浮点字面字面,但确实定义了浮点恒定,因此该术语使用。
From C17 § 5.2.4.2.2 11
FLT_DECIMAL_DIG, DBL_DECIMAL_DIG, LDBL_DECIMAL_DIG
pmax log10 b: if
b
is a power of 101 + pmax log10 b: otherwise
Each range of binary floating point like [1.0 ... 2.0), [128.0 ... 256.0), [0.125 ... 0.5) contains 2p - 1 values uniformly distributed. e.g. With
float
, p = 24.Each range of a decade of decimal text with
n
significant digits in exponential notation like [1.0 ... 9.999...), [100.0f ... 999.999...), [0.001 ... 0.00999...) contains 10n - 1 values uniformly distributed.Example: common
float
:When
p
is 24 with 224 combinations,n
must at least 8 to form the 16,777,216 combinations to distinctly round-tripfloat
to decimal text tofloat
. As the end-points of two decimal ranges above may exist well within that set of 224, the larger decimal values are spaced out further apart. This necessitates a +1 decimal digit.Example:
Consider the 2 adjacent
float
valuesBoth convert to 8 significant digits decimal text
"10.000010"
. 8 is not enough.9 is always enough as we do not need more than 167,772,160 to distinguish 16,777,216
float
values.OP also asks about
8388609.499
. (Let us only considerfloat
for simplicity.)That value is nearly half-way between 2
float
values.OP reports: "You can see 8388609.499 needs more than 9 digits to be most accurately converted to float."
And let us review the title "What is the minimum number of significant decimal digits in a floating point literal*1 to represent the value as correct as possible?"
This new question part emphasizes that the value in question is the value of the source code
8388609.499
and not the floating point constant it becomes in emitted code:8388608.0f
.If we consider the value to be the value of the floating point constant, only up to 9 significant decimal digits are needed to define the floating point constant
8388608.0f
. 8388608.49, as source code is sufficient.But to get the closest floating point constant based on some number as code yes indeed could take many digits.
Consider the typical smallest
float
,FLT_TRUE_MIN
with the exact decimal value of :Half way between that and 0.0 is 0.000..(~39 more zeroes)..0007006..(~ 100 more digits)..15625.
It that last digit was 6 or 4, the closest
float
would beFLT_TRUE_MIN
or0.0f
respectively. So now we have a case where 109 significant digits are "needed" to select between 2 possiblefloat
.To forego us going over the cliffs of insanity, IEEE-758 has already addressed this.
The number of significant decimal digits a translation (compiler) must examine to be compliant with that spec (not necessarily the C spec) is far more limited, even if the extra digits could translate to another FP value.
IIRC, it is in effect
FLT_DECIMAL_DIG + 3
. So for a commonfloat
, as little as 9 + 3 significant decimal digits may be examined.[Edit]
correct rounding is only guaranteed for the number of decimal digits required plus 3 for the largest supported binary format.
*1 C does not define: floating point literal, but does define floating point constant, so that term is used.
不能保证C标准,即浮点字面的任何数量的小数位数都会产生以浮点格式实际表示的最接近的值。在讨论浮点文字时,C 2018 6.4.4.2 3说:
对于质量,C实施应正确圆形浮点。文字达到最近的代表值,并与数字均匀的数字有联系。在这种情况下,
flt_decimal_dig
,dbl_decimal_dig
和ldbl_decimal_dig
值值值&lt; float.h&gt; gt;
提供数字提供数字提供数字总是足以唯一地识别代表价值的数字。您需要在编译器文档中对此效果的陈述,例如它为浮点文字提供了正确的舍入语句,并且它使用IEEE-754 Binary32(又称“单个精度”)用于
float
(或仅需要九个重要数字才能唯一识别所有代表值的其他格式)。C标准表示上述常数为 p log10 b 如果 b 是十的幂ceil(1 + p log 10 b )否则,其中 p 是浮动 - 点格式和 b 是格式中使用的碱。这些总是足够的,但是后者并不总是必要的。如果指数范围未绑定,则后者提供了所需的数字数。它的“ 1 +”涵盖了 b 的力量如何与10的力量相互作用的所有可能津贴。但是任何浮点格式都有有限的指数范围,并且对于指数范围的某些选择,CEIL( p log 10 b )将足够而不是CEIL(1 + p log 10 b )。没有简单的公式。它不会以标准IEEE-754格式发生,并且可以在实践中忽略。
There is no guarantee from the C standard that any number of decimal digits in a floating-point literal will produce the nearest value actually representable in the floating-point format. In discussing floating-point literals, C 2018 6.4.4.2 3 says:
For quality, C implementations should correctly round floating-point literals to the nearest representable value, with ties going to the choice with the even low digit. In that case, the
FLT_DECIMAL_DIG
,DBL_DECIMAL_DIG
, andLDBL_DECIMAL_DIG
values defined in<float.h>
provide numbers of digits that always suffice to uniquely identify a representable value.You need statements to this effect in the compiler documentation, such as statements that it provides correct rounding for floating-point literals and that it uses IEEE-754 binary32 (a.k.a. “single precision”) for
float
(or some other format that would only require nine significant digits to uniquely identify all representable values).The C standard indicates the constants above are calculated as p log10 b if b is a power of ten and ceil(1 + p log10 b) otherwise, where p is the number of digits in the floating-point format and b is the base used in the format. These always suffice, but the latter is not always necessary. The latter provides the number of digits needed if the exponent range were unbounded; its “1 +” covers all possible allowances for how the powers of b interact with the powers of 10, in a sense. But any floating-point format has a finite exponent range, and, for some choices of exponent range, ceil(p log10 b) would suffice instead of ceil(1 + p log10 b). There is no simple formula for this. It does not occur with the standard IEEE-754 formats and can be neglected in practice.