我尝试了以下代码片段,输出令我感到惊讶:
#include <stdio.h>
#include <math.h>
int main()
{
double num;
unsigned char ch;
ch = 19;
num = 1.0E+20 ;
num += ch * 1.0E+18;
printf("E18 = %lf \n",num);
printf("E18 = %e \n",num);
num = 11.0E+21 ;
num += ch * 1.0E+19;
printf("E19 = %lf <------\n",num);
printf("E19 = %e <------\n",num);
num = 11.0E+22 ;
num += ch * 1.0E+20;
printf("E20 = %lf\n",num);
printf("E20 = %e\n",num);
num = 11.0E+23 ;
num += ch * 1.0E+21;
printf("E21 = %lf\n",num);
printf("E21 = %e\n",num);
num = 11.0E+24 ;
num += ch * 1.0E+22;
printf("E22 = %lf <------\n",num);
printf("E22 = %e <------\n",num);
return 0;
}
该计划的输出:
E18 = 119000000000000000000.000000
E18 = 1.190000e+20
E19 = 11190000000000000524288.000000 <------
E19 = 1.119000e+22 <------
E20 = 111900000000000001048576.000000
E20 = 1.119000e+23
E21 = 1119000000000000044040192.000000
E21 = 1.119000e+24
E22 = 11189999999999999366660096.000000 <------
E22 = 1.119000e+25 <------
为什么数据在以指数形式打印时损坏
答案 0 :(得分:6)
因为,当数字变得足够大时,你会失去精确度:http://en.wikipedia.org/wiki/Floating_point
答案 1 :(得分:3)
数据未损坏;这就是浮点值在当今计算机中的作用。将浮点数视为固定的位数(尾数)和另一个指示小数点应放置位置的数字(指数)。对于更长,更准确的故事,Wikipedia is a good start。
由于尾数的位数是固定的,因此它不能代表你在这里要求的极小部分。此外,因为它全部是二进制的,所以不能总是精确地表示十进制数字。
指数表示法只是将已知数字不准确的最后几位数字四舍五入,因此得出结果。
答案 2 :(得分:0)
双/浮点数随着它们变大而失去精确度 - 除了Tuomas发布的the Wikipedia article之外,这是另一个好的:
http://www.yoda.arachsys.com/csharp/floatingpoint.html
它的目标是.NET,但原则仍然适用。
答案 3 :(得分:0)
浮点数据类型使用有限数量的位来表示特定范围的数字。但是,在任何两个实数m和n之间可以存在无限数量的值。所以,你牺牲了精确度。
它以指数形式显示,因为并非所有数字都被打印出来。
作为测试,尝试使用大约10位小数打印值0.2,您将看到存储的值更像是0.1999999 ....
答案 4 :(得分:0)
您正在看到浮点固有的不精确性。
某些printf
次转化可确保生成足够的有效数字,以唯一标识要打印的数字。这意味着如果有任何不精确,你会看到它。相反,默认的%e
/ %f
表示通过舍入来隐藏不精确。
据我所知,%a
(十六进制浮点)是实现此目的的唯一方法。根据{{3}},%lf
被定义为与%f
做同样的事情,即
l
(ell)...对后续的a,A,e,E,f,F,g或G转换说明符没有影响。
所以这在技术上是标准库中的一个错误。