让我们考虑以下代码:
#include <stdio.h>
int main()
{
float x = 0.33;
printf("%.100f",x);
return 0;
}
如果 float 有 6 位精度,如何用
printf
显示超过 6 位?
您尝试将小数 0.33 转换为
float
。但是,与大多数小数一样,数字 0.33 无法在类型 float
内部使用的二进制表示中精确表示。您可以获得的最接近的是二进制分数0.0101010001111010111000011
。这个分数,如果我们把它转换回十进制,正好是 0.3300000131130218505859375.
在十进制中,如果我告诉你你有 7 位有效数字,你尝试表示数字 1/3 = 0.333…,你期望得到 0.333333300000。也就是说,您希望获得一些与原始数字相匹配的有效数字,然后在没有足够意义的地方加上 0。二进制分数的工作方式相同:对于类型
float
,二进制分数总是恰好有 24 位有效位,后跟(如果你愿意的话)任意数量的二进制 0。
当我们将该二进制数转换回十进制时,我们得到大约 7 位数字与我们认为的十进制数相匹配,后面不是零,而是看起来像随机数字的数字。例如,二进制
float
的 1/3 是 0.0101010101010101010101011000000000
(注意 24 位有效位),转换为十进制时是 0.333333343267440795898437500000(注意 7 位精确数字)。
当您听到类型
float
具有大约 7 位有效数字时,这确实 not 意味着您将获得原始数字的 7 位,后跟 0。这意味着你会得到 approximately 原始号码的 7 位数字(但可能是 6 位,或者可能是 8 位或 9 位或更多),然后是一些可能与您的原始号码不匹配但不匹配的数字全0,要么。但这实际上不是问题,特别是如果(按照推荐和适当的方式)将此数字四舍五入到有用的数字。这可能是一个问题(虽然这经常出现)是当你用无用的数字打印回数字时,格式如%.100f
,你会看到一些看起来很奇怪的数字全部为 0,这让你感到困惑,就像这里一样。
类型
float
和 double
在内部使用二进制表示的事实会导致像这样的无尽惊喜。用二进制表示并不奇怪(我们都知道计算机用二进制做所有事情),但是二进制fractions无法准确表示我们习惯的小数,这真是令人惊讶。请参阅规范的 SO 问题浮点数学是否损坏?了解更多信息。
如果float有6位精度,为什么我们可以用
显示6位以上的float?printf
A
float
每个定义都没有 6 位精度。您已选择显示比实现可能提供的更多的数字 - 它提供了。
为什么我们可以用
显示6位以上的浮点数?printf
您可以告诉程序显示您在
float
/double
/long double
中的任何内容,它仍然是一个近似值。
显示这样一个变量的当前内容最好在调试时完成。
“如果浮点数有 6 位精度……”--> 是一个弱前提。
float'
没有6位的十进制精度,而是24位的二进制精度。
怎么可能用
(?)显示超过6位数字printf
当以十进制形式打印二进制浮点数时,每个二进制数字都会贡献一些 2 的幂,例如 ..., 16, 8, 4, 2, 1, 0.5, 0.25, 0.125, 0.0625, ...
这些 2 的幂的总和很容易超过 6 位小数。
在极端情况下,
FLT_TRUE_MIN
通常具有以下精确值:
0.00000000000000000000000000000000000000000000140129846432481707092372958328991613128026194187651577175706828388979108268586060148663818836212158203125
很少有 9 位有效的小数位更重要。