如果float有6位精度,为什么我们可以用printf显示超过6位的浮点数?

Zar*_*uta 2 c floating-point precision

让我们考虑下面的代码:

#include <stdio.h>
int main()
{
    float x = 0.33;
    printf("%.100f",x);

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

如果float有6位精度,那么如何用 来显示超过6位的数字printf

Ste*_*mit 6

您尝试将小数 0.33 转换为float. 但是,与大多数十进制分数一样,数字 0.33 无法在 type 内部使用的二进制表示形式中精确表示float。您可以获得的最接近的是二进制分数0.0101010001111010111000011。如果我们将其转换回十进制,该分数正好是 0.3300000131130218505859375。

\n

在十进制中,如果我告诉你有 7 位有效数字,并且你尝试表示数字 1/3 = 0.333\xe2\x80\xa6,你期望得到 0.333333300000。也就是说,您期望得到一些与原始数字匹配的有效数字,后面跟着 0,因为没有足够的重要性。二进制分数的工作方式相同:对于 type float,二进制分数始终具有 24 位有效位,后跟(如果您愿意)任意数量的二进制 0。

\n

当我们将该二进制数转换回十进制数时,我们会得到大约 7 位与我们认为的十进制数相匹配的数字,后面不是零,而是看起来像随机数字的数字。例如,二进制的 1/3 为float0.0101010101010101010101011000000000注意 24 个有效位),转换为十进制后为 0.333333343267440795898437500000(注意 7 个精确数字)。

\n

当您听说该类型float有大约 7 位有效数字时,这并不意味着您将获得原始号码的 7 位数字,后跟 0。这意味着您将获得原始号码的大约7 位数字(但可能是 6 位,也可能是 8 位、9 位或更多),后面跟着一些可能与您的原始号码不匹配但与您的原始号码不匹配的数字。也不都是 0。但这实际上并不是问题,特别是如果(按照建议和正确的方式)您将这个数字打印回四舍五入到有用的位数。当它可能成为问题时(尽管这种情况经常出现),是当您使用无用的数字(格式如 )打印回数字时%.100f,您会看到一些看起来奇怪的数字,这些数字并不全部0,这让你感到困惑,就像这里一样。

\n

事实上,在内部输入floatdouble使用二进制表示会导致无尽的惊喜。表示形式是二进制的并不奇怪(我们都知道计算机以二进制来做所有事情),但是二进制分数无法准确地表示我们习惯的十进制分数,这确实令人惊讶。请参阅规范的 SO 问题浮点数学是否已损坏?了解更多相关信息。

\n