输出应该是什么 printf("%.5g", 0.00390625)

What should be the output printf("%.5g", 0.00390625)

在试验将双精度转换为文本的代码时,我正在将例程的结果与标准库中的结果进行比较。对于标题中的数字和格式,我的套路returns

0.0039062

libgcc printf 打印出相同的结果。但是,Microsoft C++(构建工具 2019)说

0.0039063

我相信微软的库是有错误的,每轮都要平分。我说得对吗?

C 标准说结果必须正确舍入,但没有明确说明舍入规则是什么。

一些预备知识:.00390625 = 2−8 如果使用二进制或十进制格式,则可以在 double 中精确表示,因为 DECIMAL_DIG(已声明in <float.h>) 必须至少为 10,这意味着精度足以准确表示。 (理论上,double 可以有另一个基数,比如 3,那么 .00390625 就不能准确表示。这个答案不讨论这种情况。)

C 2018 7.21.6.1 7 表示使用此数字的 %.5g 转换将使用 f 样式。对于 f 样式,它表示“...该值四舍五入到适当的位数。”

C 2018 7.21.6.1 13 表示“对于 eEfFgG转换,如果有效小数位数最多DECIMAL_DIG,则结果应该正确四舍五入……”五当然小于十,所以结果应该正确四舍五入。

“正确舍入”在 3.9 中定义为“根据当前舍入模式,在值上最接近结果格式的表示形式,结果将被赋予无限范围和精度”。对于 printf 转换,结果格式为十进制数字。这个定义有效地告诉我们转换中不应该有算术错误。

在5.2.4.2.2 9中,标准规定了一些舍入方法,包括“向零”、“最接近”、“向正无穷大”和“向负无穷大”,并允许实现定义其他舍入模式。在大多数情况下,舍入模式控制内置算术和强制转换运算符。但是,它还应该管理 printf 转换。 (理想情况下,它还会管理 sin 等数学库例程,但很少实现这些例程以遵守舍入模式。)

因此,“.0039063”的输出可能是使用“朝向正无穷大”的舍入模式产生的。但是,我假设您的 Microsoft 实现使用默认的“最接近”舍入模式。您可以通过打印 FLT_ROUNDS 来测试它; “到最近”为 1。

但是,C 标准没有具体说明“最接近”方法对关系的作用,只是附件 F 将其绑定到 IEEE-754 最接近方法,该方法解决了有利于候选人的关系甚至低位数。但是,附件 F 是可选的;使用它不需要 C 实现。

因此,C 标准在技术上并未指定使用“最接近”方法将 .00390625 舍入为五位有效数字的行为。