Adam
Adam

Reputation: 1386

Why snprintf changes output string?

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

Upvotes: 0

Views: 162

Answers (3)

chux
chux

Reputation: 153498

When printing more than DBL_DIG significant decimal digits, the effects of a double finite format may appear.

Example:

#include <float.h>

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 has 15 significant decimal digits. (14 to the right of '.')


Regardless of the base (2, 10, 16, etc.) used for a double, only so many decimal digits are "round-trip"-able.

Example: (Assuming DBL_DIG is 10, the minimum specified by C)

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

Should the user entered "12345678901234567890", the output would be "1.234567890e19" and "1.234567890?????e19", the "?????" not begin specified by C.

Upvotes: 0

Drew McGowen
Drew McGowen

Reputation: 11706

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!

Upvotes: 5

David Ranieri
David Ranieri

Reputation: 41017

Cast to a long double in order to get more precision:

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

Output:

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 

Upvotes: 1

Related Questions