您的实现打印的字符串显示了示例中双精度的确切值,这是 C 标准允许的,如下所示。
首先,我们应该了解浮点对象代表什么。C 标准在这方面做得很差,但是,假设您的实现使用 IEEE 754 浮点标准,正常的浮点对象恰好表示(-1) s •2 e •(1+f) 用于某些符号位s(0 或 1)、指数 e(在特定类型的范围内,双精度为 -1022 到 1023)和小数 f(也在范围内,双精度小数点后的 52 位)。许多人使用对象来近似附近的值,但根据标准,对象仅代表它定义的一个值。
您显示的值 0.7071067811865474617150085 可以完全表示为双精度(符号位 0、指数 -1 和小数位 [十六进制] .6a09e667f3bcc 16)。重要的是要了解具有此值的双精度值恰好代表该值;它不代表附近的值,例如 0.707106781186547461715。
现在我们知道传递给 的值fprintf
,我们可以考虑 C 标准对此有何规定。首先,C 标准定义了一个名为 DECIMAL_DIG 的常量。C 2011 5.2.4.2.2 11 将其定义为小数位数,以便最广泛支持的类型中的任何浮点数都可以四舍五入到那么多十进制数字并再次返回而无需更改值。您传递给fprintf
25 的精度可能大于系统上 DECIMAL_DIG 的值。
在 C 2011 7.21.6.1 13 中,标准规定“如果有效十进制数字的数量超过 DECIMAL_DIG 但源值可以用 DECIMAL_DIG 数字精确表示,那么结果应该是带有尾随零的精确表示。否则,源值由两个相邻的十进制字符串 L < U 限定,两者都具有 DECIMAL_DIG 有效数字;得到的十进制字符串 D 的值应满足 L ≤ D ≤ U,并额外规定误差应具有当前舍入方向的正确符号。”</p>
这种措辞允许编译器有一些回旋余地。目的是结果必须足够准确,以便可以无错误地转换回原始双精度。它可能更准确,并且某些 C 实现将产生完全正确的值,这是允许的,因为它满足上面的段落。
顺便说一句,您显示的值不是最接近 sqrt(2)/2 的两倍。该值为 +0x1.6A09E667F3BCDp-1 = 0.70710678118654757273731092936941422522068023681640625。