1

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.

  • There is no such thing as _"a large integer with a decimal point at the end"_. That's a `double`. – Asteroids With Wings Jul 20 '20 at 11:52
  • "a large integer with a decimal point at the end" is a contradictio in teminis because the point at the end means it is a floating point number. Hence the compiler converted it to such. Then converting it back to long long int introduced imprecision. – Paul Ogilvie Jul 20 '20 at 11:53
  • It wasn't even converted; it was always a `double`. :) – Asteroids With Wings Jul 20 '20 at 11:53
  • 1
    I wanted to emphasize that the number has a large number of digits on the left hand side of the decimal and zero on the right side. – DeusExMachina Jul 20 '20 at 11:58
  • 2
    [The GNU MP Bignum Library](https://gmplib.org/) is a good way to deal with large integers. – MikeCAT Jul 20 '20 at 12:18
  • The type you give is `double` which holds about 17 decimal digits accurately. Casting to `(long double)` does not change that, it is already `double` by then. Without a suffix, the evaluation depends on `FLT_EVAL_METHOD`. Otherwise you would have to specify, eg, `11111111111111111111.0L`. – Weather Vane Jul 20 '20 at 12:31
  • Note too that `double` only has 53 bits of significance, against the 64 bits of `unsigned long long`. – Weather Vane Jul 20 '20 at 12:34
  • @DeusExMachina: If a numeric literal contains a decimal point, then no matter how many leading *or* trailing digits are present it's treated as a `double`, not an integer type. – John Bode Jul 20 '20 at 12:42
  • @WeatherVane How do I add a suffix `L` if the number is already stored in a variable? – DeusExMachina Jul 20 '20 at 13:02
  • @DeusExMachina You don't add suffices to a variable. The suffix marks the literal as being of a certain type. The variable has a type already. – the busybee Jul 20 '20 at 13:13
  • @thebusybee Actually I want to know what should I do in case, for example, if I want to use the integer (mathematically) output from `sqrtl(long double variable)`? – DeusExMachina Jul 20 '20 at 13:33
  • 1
    DeusExMachina to use the whole number part of `sqrtl()`, --> `long double wp = roundl(sqrt(...))` or research `frexpl()`. – chux - Reinstate Monica Jul 20 '20 at 15:00

0 Answers0