While writing a program I came across a case where a large integer with a decimal point at the end is printed with different values when casted with different data types. A minimal working example is
#include<stdio.h>
int main(){
printf("15-digits \t %ld \t %ld \t %lld\n", 111111111111111, (long int) 111111111111111.0, (long long int)111111111111111.0);
printf("16-digits \t %ld \t %ld \t %lld\n", 1111111111111111, (long int) 1111111111111111.0, (long long int)1111111111111111.0);
printf("17-digits \t %ld \t %ld \t %lld\n", 11111111111111111, (long int) 11111111111111111.0, (long long int)11111111111111111.0);
printf("18-digits \t %ld \t %ld \t %lld\n", 111111111111111111, (long int) 111111111111111111.0, (long long int)111111111111111111.0);
printf("19-digits \t %ld \t %ld \t %lld\n", 1111111111111111111, (long int) 1111111111111111111.0, (long long int)1111111111111111111.0);
printf("19-digits \t %ld \t %Lf \t %Lf\n", 1111111111111111111, (long double) 1111111111111111111.0, (long double)1111111111111111111.0);
}//main
This code produces the following output:
$ gcc int_length.c -o int_length && ./int_length
15-digits 111111111111111 111111111111111 111111111111111
16-digits 1111111111111111 1111111111111111 1111111111111111
17-digits 11111111111111111 11111111111111112 11111111111111112
18-digits 111111111111111111 111111111111111104 111111111111111104
19-digits 1111111111111111111 1111111111111111168 1111111111111111168
19-digits 1111111111111111111 1111111111111111168.000000 1111111111111111168.000000
Here you can see that numbers with 17+ digits are printed incorrectly when they have decimal point at the end.
So my first question is, why is this happening and what should I do to print them correctly?
Another problem is that I am getting warnings while compiling the following code:
#include<stdio.h>
int main(){
printf("20-digits \t %llu \t %lu \t %llu\n", 11111111111111111111, (unsigned long int) 11111111111111111111.0, (unsigned long long int)11111111111111111111.0);
printf("20-digits \t %llu \t %Lf \t %Lf\n", 11111111111111111111, (long double) 11111111111111111111.0, (long double)11111111111111111111.0);
}//main
$ gcc int_length.c -o int_length && ./int_length
int_length.c: In function ‘main’:
int_length.c:5:48: warning: integer constant is so large that it is unsigned
printf("20-digits \t %llu \t %lu \t %llu\n", 11111111111111111111, (unsigned long int) 11111111111111111111.0, (unsigned long long int)11111111111111111111.0);
^~~~~~~~~~~~~~~~~~~~
int_length.c:5:27: warning: format ‘%llu’ expects argument of type ‘long long unsigned int’, but argument 2 has type ‘__int128’ [-Wformat=]
printf("20-digits \t %llu \t %lu \t %llu\n", 11111111111111111111, (unsigned long int) 11111111111111111111.0, (unsigned long long int)11111111111111111111.0);
~~~^
int_length.c:6:47: warning: integer constant is so large that it is unsigned
printf("20-digits \t %llu \t %Lf \t %Lf\n", 11111111111111111111, (long double) 11111111111111111111.0, (long double)11111111111111111111.0);
^~~~~~~~~~~~~~~~~~~~
int_length.c:6:27: warning: format ‘%llu’ expects argument of type ‘long long unsigned int’, but argument 2 has type ‘__int128’ [-Wformat=]
printf("20-digits \t %llu \t %Lf \t %Lf\n", 11111111111111111111, (long double) 11111111111111111111.0, (long double)11111111111111111111.0);
~~~^
20-digits 11111111111111111111 0 11111111111111110656
20-digits 11111111111111111111 11111111111111110656.000000 11111111111111110656.000000
I am getting the warnings despite of the fact that the 20-digits number 11111111111111111111
is smaller than ULONG_MAX
or ULLONG_MAX
defined in limits.h
. Both of them are equal to 18446744073709551615
(20-digits).
My general question is how do you deal with very large numbers (20+ digits) in C?
I have gcc version 7.5.0
.