在尝试将 double 转换为文本的代码时,我将例程的结果与标准库中的结果进行比较。对于标题中的数字和格式,我的例程返回
0.0039062
libgcc printf 打印相同的结果。但是,Microsoft C++(构建工具 2019)说
0.0039063
我相信微软的图书馆是错误的,每轮甚至规则。我对吗?
在尝试将 double 转换为文本的代码时,我将例程的结果与标准库中的结果进行比较。对于标题中的数字和格式,我的例程返回
0.0039062
libgcc printf 打印相同的结果。但是,Microsoft C++(构建工具 2019)说
0.0039063
我相信微软的图书馆是错误的,每轮甚至规则。我对吗?
C 标准规定结果必须正确舍入,但并未明确说明舍入规则是什么。
一些初步准备: .00390625 = 2 -8double
如果使用二进制或十进制格式,则可以精确表示,因为DECIMAL_DIG
(在 中声明<float.h>
)必须至少为 10,这意味着精度足以精确表示。(理论上, adouble
可能有另一个基数,例如 3,然后 .00390625 不能完全表示。这个答案不讨论这种情况。)
C 2018 7.21.6.1 7 表示%.5g
使用此数字的转换将使用该f
样式。对于f
样式,它表示“......该值被四舍五入到适当的位数。”</p>
C 2018 7.21.6.1 13 说“对于e
, E
, f
, F
, g
, 和G
转换,如果有效小数位数最多为DECIMAL_DIG
,则结果应正确四舍五入……” 五当然小于十,所以结果应该是正确舍入。
“正确舍入”在 3.9 中定义为“以最接近值的结果格式表示,受当前舍入模式的影响,结果将被赋予无限范围和精度”。出于printf
转换目的,结果格式是十进制数字。这个定义有效地告诉我们在转换中不应该有算术错误。
在 5.2.4.2.2 9 中,标准规定了一些舍入方法,包括“向零”、“向最近”、“向正无穷大”和“向负无穷大”,并允许实现定义其他舍入模式。在大多数情况下,舍入模式控制内置算术和强制转换运算符。但是,它也应该管理printf
转换。(理想情况下,它还可以管理数学库例程,例如sin
,但很少实施这些例程以遵守舍入模式。)
因此,“.0039063”的输出可能是由于使用了“向正无穷大”的舍入模式。但是,我假设您的 Microsoft 实现使用“到最近”的默认舍入模式。您可以通过打印来测试它FLT_ROUNDS
;“到最近”的值为 1。
然而,C 标准没有具体说明“到最近”方法对关系的作用,除了附件 F 将其绑定到 IEEE-754 到最近方法,该方法以偶数低位的候选者为优势解决关系。但是,附件 F 是可选的;使用它不需要 C 实现。
因此,使用“最接近”方法将 .00390625 舍入到五个有效数字的行为在技术上并未由 C 标准指定。