我在C中有这个代码,我已经宣布0.1为double .
#include <stdio.h>
int main() {
double a = 0.1;
printf("a is %0.56f\n", a);
return 0;
}
这就是它打印的内容, a is 0.10000000000000001000000000000000000000000000000000000000
C中的代码相同,
#include <iostream>
using namespace std;
int main() {
double a = 0.1;
printf("a is %0.56f\n", a);
return 0;
}
这就是它的印刷品, a is 0.1000000000000000055511151231257827021181583404541015625
有什么不同?当我读到两个都被分配8个字节? C如何在小数位上打印更多数字?
另外,它怎么能到小数点55位? IEEE 754浮点只有52位的小数,我们可以得到15位十进制数的精度 . 它以二进制形式存储 . 为什么它的十进制解释存储更多?
2 回答
使用MinGW g(和gcc)7.3.0,您的结果将被准确复制 .
这是一个非常奇怪的未定义行为案例 .
未定义的行为是由于使用
printf
而没有包含适当的 Headers ,¹违反“应该”C++17 §20.5.2.2
在C代码更改
<iostream>
到<stdio.h>
,以获得有效的C代码,并获得与C程序相同的结果 .为什么C代码甚至可以编译?
好吧,与C不同,在C中,允许标准库头在任何其他头中拖动 . 显然,在
printf
的某些声明中,<iostream>
Headers 拖拽 . 只是不完全正确 .详细信息:使用MinGW g 7.3.0时,
printf
的声明/定义取决于宏符号 __USE_MINGW_ANSI_STDIO . 默认只是<stdio.h>
声明printf
. 但是当__USE_MINGW_ANSI_STDIO
被定义为逻辑真时,<stdio.h>
提供了printf
的覆盖定义,即__mingw_vprintf
. 当发生这种情况时,<cstdio>
标头在包含<stdio.h>
之前定义(通过间接包含)__USE_MINGW_ANSI_STDIO
.<_mingw.h>
,"Note that we enable it also for _GNU_SOURCE in C++, but not for C case."中有评论 .在C中,使用此编译器的相关版本,包含
<stdio.h>
和使用printf
,或包括<cstdio>
,说using std::printf;
和使用printf
之间实际上存在差异 .关于
......只是十进制表示更长 . 超出内部表示精度的数字,对于64位IEEE 754约为15位,基本上是垃圾,但它们可用于精确地重构原始位 . 在某些时候,它们将变为全零,并且达到C程序输出中最后一位的那一点 .
1感谢Dietrich Epp发现标准报价 .
在我看来,两种情况都打印56位小数,所以问题在技术上是基于一个有缺陷的前提 .
我也看到两个数字在52位精度范围内等于
0.1
,因此两者都是正确的 .这导致你的最终问题,"How come its decimal interpretation stores more?" . 它不存储更多小数 .
double
不存储任何小数 . 它存储位 . 生成小数 .