为什么snprintf会改变输出字符串?

我尝试使用snprintf将一些数字转换为字符串。 name1在逗号后应与name2具有相同的数字。

#include  #define length 50 int main() { char name1 [length]; char name2 [length]; double step= 0.00001; unsigned long long int iterMax =100000000000; int k; for (k = 0; k <= 20; k++) { printf("numbers : k = %2d ; k*step = %f ;", k, k*step); snprintf(name1,length+1,"%f", iterMax+k*step); /* */ snprintf(name2,length+1, " %f", k*step); /* */ printf("strings : k*step = %s ; iterMax+k*step = %s \n",name2, name1); } return 0; } 

编译它:

  gcc tc -Wall 

输出是:

 ./a.out numbers : k = 0 ; k*step = 0.000000 ;strings : k*step = 0.000000 ; iterMax+k*step = 100000000000.000000 numbers : k = 1 ; k*step = 0.000010 ;strings : k*step = 0.000010 ; iterMax+k*step = 100000000000.000015 numbers : k = 2 ; k*step = 0.000020 ;strings : k*step = 0.000020 ; iterMax+k*step = 100000000000.000015 numbers : k = 3 ; k*step = 0.000030 ;strings : k*step = 0.000030 ; iterMax+k*step = 100000000000.000031 numbers : k = 4 ; k*step = 0.000040 ;strings : k*step = 0.000040 ; iterMax+k*step = 100000000000.000046 

当iterMax较小时,结果是相同的(数字aftter逗号),例如100000000:

 numbers : k = 0 ; k*step = 0.000000 ;strings : k*step = 0.000000 ; iterMax+k*step = 100000000.000000 numbers : k = 1 ; k*step = 0.000010 ;strings : k*step = 0.000010 ; iterMax+k*step = 100000000.000010 numbers : k = 2 ; k*step = 0.000020 ;strings : k*step = 0.000020 ; iterMax+k*step = 100000000.000020 numbers : k = 3 ; k*step = 0.000030 ;strings : k*step = 0.000030 ; iterMax+k*step = 100000000.000030 numbers : k = 4 ; k*step = 0.000040 ;strings : k*step = 0.000040 ; iterMax+k*step = 100000000.000040 

ULLONG_MAX = 18446744073709551615比iterMax大。

我怎么解决这个问题?

TIA

这实际上是double精度问题。 还有很多其他问题可以解释更多有关IEEE-754浮点数的问题,但我将在此总结相关要点:

  1. double和family有效地以科学记数法存储数字,精度有限。 这意味着数字越大,它的准确度就越低。
  2. 大多数数字使用基数2.因此,小数0.1不能精确存储(相反,它类似于0.10000000149011612

因此,数字100000000000.000010是“大”,因此在小数位后变得不太准确。 事实上,一旦你走向约4503599627370496 ,你甚至不能存储所有整数!

为了获得更高的精度,转换为long double精度:

 snprintf(name1,length+1,"%Lf", (long double)iterMax+k*step); 

输出:

 numbers : k = 0 ; k*step = 0.000000 ;strings : k*step = 0.000000 ; iterMax+k*step = 100000000000.000000 numbers : k = 1 ; k*step = 0.000010 ;strings : k*step = 0.000010 ; iterMax+k*step = 100000000000.000010 numbers : k = 2 ; k*step = 0.000020 ;strings : k*step = 0.000020 ; iterMax+k*step = 100000000000.000020 numbers : k = 3 ; k*step = 0.000030 ;strings : k*step = 0.000030 ; iterMax+k*step = 100000000000.000030 numbers : k = 4 ; k*step = 0.000040 ;strings : k*step = 0.000040 ; iterMax+k*step = 100000000000.000040 numbers : k = 5 ; k*step = 0.000050 ;strings : k*step = 0.000050 ; iterMax+k*step = 100000000000.000050 numbers : k = 6 ; k*step = 0.000060 ;strings : k*step = 0.000060 ; iterMax+k*step = 100000000000.000060 numbers : k = 7 ; k*step = 0.000070 ;strings : k*step = 0.000070 ; iterMax+k*step = 100000000000.000070 numbers : k = 8 ; k*step = 0.000080 ;strings : k*step = 0.000080 ; iterMax+k*step = 100000000000.000080 numbers : k = 9 ; k*step = 0.000090 ;strings : k*step = 0.000090 ; iterMax+k*step = 100000000000.000090 numbers : k = 10 ; k*step = 0.000100 ;strings : k*step = 0.000100 ; iterMax+k*step = 100000000000.000100 numbers : k = 11 ; k*step = 0.000110 ;strings : k*step = 0.000110 ; iterMax+k*step = 100000000000.000110 numbers : k = 12 ; k*step = 0.000120 ;strings : k*step = 0.000120 ; iterMax+k*step = 100000000000.000120 numbers : k = 13 ; k*step = 0.000130 ;strings : k*step = 0.000130 ; iterMax+k*step = 100000000000.000130 numbers : k = 14 ; k*step = 0.000140 ;strings : k*step = 0.000140 ; iterMax+k*step = 100000000000.000140 numbers : k = 15 ; k*step = 0.000150 ;strings : k*step = 0.000150 ; iterMax+k*step = 100000000000.000150 numbers : k = 16 ; k*step = 0.000160 ;strings : k*step = 0.000160 ; iterMax+k*step = 100000000000.000160 numbers : k = 17 ; k*step = 0.000170 ;strings : k*step = 0.000170 ; iterMax+k*step = 100000000000.000170 numbers : k = 18 ; k*step = 0.000180 ;strings : k*step = 0.000180 ; iterMax+k*step = 100000000000.000180 numbers : k = 19 ; k*step = 0.000190 ;strings : k*step = 0.000190 ; iterMax+k*step = 100000000000.000190 numbers : k = 20 ; k*step = 0.000200 ;strings : k*step = 0.000200 ; iterMax+k*step = 100000000000.000200 

当打印超过DBL_DIG有效十进制数字时,可能会出现double有限格式的效果。

例:

 #include  printf("%d\n", DBL_DIG); printf("%.*e\n", DBL_DIG - 1, 100000000000.0 + 0.00001); printf("%.*e\n", DBL_DIG - 1 + 10, 100000000000.0 + 0.00001); 15 1.00000000000000e+11 1.000000000000000152587891e+11 

1.00000000000000e+11有15位有效小数。 (’。’右侧14)


无论用于double精度的基数(2,10,16等),只有这么多的十进制数字是“往返”的。

示例:(假设DBL_DIG为10,C指定的最小值

 double x; scanf("%lf", &x); printf("%.*e\n", DBL_DIG - 1, x); printf("%.*e\n", DBL_DIG - 1 + 5, x); 

如果用户输入“12345678901234567890”,输出将为“1.234567890e19”和“1.234567890 ????? e19”,即“?????” 不是由C指定的。