C语言 printf 和 scanf 如何处理浮点精度格式?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/3789997/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How do printf and scanf handle floating point precision formats?
提问by ultimate cause
Consider the following snippet of code:
考虑以下代码片段:
float val1 = 214.20;
double val2 = 214.20;
printf("float : %f, %4.6f, %4.2f \n", val1, val1, val1);
printf("double: %f, %4.6f, %4.2f \n", val2, val2, val2);
Which outputs:
哪些输出:
float : 214.199997, 214.199997, 214.20 | <- the correct value I wanted
double: 214.200000, 214.200000, 214.20 |
I understand that 214.20has an infinite binary representation. The first two elements of the first line have an approximation of the intended value, but the the last one seems to have no approximation at all, and this led me to the following question:
我知道它214.20有一个无限的二进制表示。第一行的前两个元素具有预期值的近似值,但最后一个似乎根本没有近似值,这导致我提出以下问题:
How do the scanf, fscanf, printf, fprintf(etc.) functions treat the precision formats?
如何做scanf,fscanf,printf,fprintf(等)函数将精度格式?
With no precision provided, printfprinted out an approximated value, but with %4.2fit gave the correct result. Can you explain me the algorithm used by these functions to handle precision?
没有提供精度,printf打印出一个近似值,但%4.2f它给出了正确的结果。你能解释一下这些函数用来处理精度的算法吗?
回答by DarkDust
The thing is, 214.20 cannot be expressed exactlywith binary representation. Few decimal numbers can. So an approximation is stored. Now when you use printf, the binary representation is turned into a decimal representation, but it again cannot be expressed exactly and is only approximated.
问题是,214.20 不能用二进制表示完全表达。很少有十进制数可以。因此存储了一个近似值。现在,当您使用 printf 时,二进制表示将转换为十进制表示,但它再次无法精确表示,只能进行近似表示。
As you noticed, you can give a precision to printf to tell it how to round the decimal approximation. And if you don't give it a precision then a precision of 6 is assumed (see the man page for details).
正如您所注意到的,您可以给 printf 一个精度来告诉它如何舍入十进制近似值。如果您不给它一个精度,则假定精度为 6(有关详细信息,请参阅手册页)。
If you use %.40ffor the float and %.40lffor the double in your example above, you will get these results:
如果您在上面的示例中使用%.40ffloat 和%.40lfdouble ,您将获得以下结果:
214.1999969482421875000000000000000000000000
214.1999999999999886313162278383970260620117
They are different because with double, there are more bits to better approximate 214.20. But as you can see, they are still very odd when represented in decimal.
它们是不同的,因为对于 double,有更多位可以更好地近似 214.20。但是正如您所看到的,当以十进制表示时,它们仍然很奇怪。
I recommend to read the Wikipedia article on floating point numbersfor more insights about how floating point numbers work. An excellent read is also What Every Computer Scientist Should Know About Floating-Point Arithmetic
我建议阅读有关浮点数的维基百科文章,以获取有关浮点数如何工作的更多见解。一本优秀的读物也是每个计算机科学家应该知道的关于浮点运算的知识
回答by R.. GitHub STOP HELPING ICE
Since you asked about scanf, one thing you should note is that POSIX requires printfand a subsequent scanf(or strtod) to reconstruct the original value exactlyas long as sufficiently significant digits (at least DECIMAL_DIG, I believe) were printed. Plain C of course makes no such requirement; the C standard pretty much allows floating point operations to give whatever result the implementor likes as long as they document it. However, if your intent is to store floating point numbers in text files to be read back later, you might be better off using the C99 %aspecifier to print them in hex. This way they'll be exact and there's no confusion about whether the serialize/deserialize process loses precision.
既然你问了一下scanf,有一件事你应该注意的是,POSIX要求printf和随后的scanf(或strtod)重建原始值完全相同,只要充分显著数字(至少DECIMAL_DIG,我相信)印。普通C当然没有这样的要求;C 标准几乎允许浮点运算给出实现者喜欢的任何结果,只要他们记录它。但是,如果您的意图是将浮点数存储在文本文件中以便稍后读回,您最好使用 C99%a说明符以十六进制打印它们。这样,它们将是准确的,并且不会混淆序列化/反序列化过程是否会失去精度。
Keep in mind thatr when I said "reconstruct the original value", I mean the actual value which was held in the variable/expression passed to printf, not the original decimal you wrote in the source file which got rounded to the best binary representation by the compiler.
请记住,当我说“重建原始值”时,我的意思是传递给 的变量/表达式中保存的实际值,而printf不是您在源文件中写入的原始十进制数,它被四舍五入为最佳二进制表示编译器。
回答by Philip Starhill
scanfwill round the input value to the nearest exactly representable floating point value. As DarkDust's answer illustrates, in single precision the closest exactly representable value is below the exact value, and in double precision the closest exactly representable value is above the exact value.
scanf将输入值四舍五入到最接近的精确可表示的浮点值。正如 DarkDust 的回答所示,在单精度中,最接近的精确可表示值低于精确值,而在双精度中,最接近的精确可表示值高于精确值。

