且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

为什么snprintf更改输出字符串?

更新时间:2022-10-16 11:58:13

$ c> double 精度。还有很多其他问题可以解释更多关于IEEE-754浮点数的问题,但我将在这里总结相关的几点:


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

例如 100000000000.000010 的数字是大,所以在小数点后面变得不准确。事实上,一旦你接近 4503599627370496 ,你甚至不能存储所有的整数!


I try to convert some numbers to string using snprintf. The name1 should have the same digits after comma as name2.

  #include <stdio.h>
  #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;
}

Compile it with :

 gcc t.c  -Wall

Output is :

./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 

The results are the same ( digits aftter comma ) when iterMax is smaller , for example 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 

The ULLONG_MAX = 18446744073709551615 is greater then iterMax.

How can I resolve that ?

TIA

This is actually a problem of double precision. There are plenty of other questions which explain more about IEEE-754 floating-point numbers, but I'll sum up the relevant points here:

  1. double and family effectively store numbers in scientific notation with limited precision. This means the larger the number, the less accurate it'll be.
  2. Most numbers use base 2. As such, the decimal 0.1 cannot be stored exactly (instead, it's something like 0.10000000149011612)

As such, the number 100000000000.000010 is "large", so it becomes less accurate after the decimal place. In fact, once you get towards about 4503599627370496, you can't even store all integers!