unsigned long long int constant value vs. multiplicative value - c

I tried the below, and it seems that 'test' results in wrong value. 2500*2500*2500 == 15625000000, why the below operations result in different outcome?
unsigned long long int test = 2500*2500*2500;
fprintf(stderr, "*************** test = %lld, %llu\n", test, test);
unsigned long long int test2 = 15625000000;
fprintf(stderr, "*************** test2 = %lld, %llu\n", test2, test2);
Result:
*************** test = -1554869184, 18446744072154682432
*************** test2 = 15625000000, 15625000000

2500 * 2500 * 2500 is never promoted past int, so the signed overflow that occurs (which is, by the way, UB) stops the correct calculation from being performed.
To allow it, you must tell the compiler that your literals are of a particular type. There are two ways to do this:
By casting—casting a literal is generally handled at compile-time and has no runtime overhead:
unsigned long long int test = (unsigned long long int)2500 * (unsigned long long int)2500 * (unsigned long long int)2500;
Note that the cast is performed on the multiplicands individually. If the result of the operation were cast (e.g. (unsigned long long int)(2500 * 2500 * 2500)) then the cast would be too late to preserve the data.
By suffixing:
unsigned long long int test = 2500ULL * 2500ULL * 2500ULL;
This is exactly as efficient at runtime as casting of literals is, but depending on usage may be easier or harder to read. Suffixing must be applied directly to a literal (it cannot be applied to the result of an operation, so (2500 * 2500 * 2500)ULL is illegal.)

2500*2500*2500 is not an unsigned long long just because you're copying it to an unsigned long long. The multiplications are done with ints, so the result of the multiplication is an int. By the time the upgrade to unsigned long long happens, it's too late. Use 2500ULL.

Related

how overflow occurs differently?

I'm new to C, still struggling in understanding how overflow occurs. Let's say we have the following buggy code to determine whether one string is longer than another:
int strlonger(char *s, char *t) {
return strlen(s) - strlen(t) > 0; // let's say the first return value of strlen(s) is s1, abd the second is s2
}
and we know it is not going to work as the return type of strlen() is size_t which is unsigned int, so when we have sth like 1u - 2u > 0;the left operand overflows.
I kind of get the idea, it is sth like 1u - 2u is -1, but because both s1 and s2 are unsigned int, the result should also be unsigned int, therefore it overflow.
But considering a different scenario:
int a= 1048577;
size_t b = 4096;
long long unsigned c= a* b;
since 1048577*4096 = 4294971392 which is out of range of int or unsigned b, so isn't that the result should overflow first? why it is like the result is reserved to keep value just because the left operand c is long long unsigned that can hold the value?, isn't that more sensible to make it work only in this way:
long long unsigned a= 1048577;
long long unsigned b = 4096;
long long unsigned c= a* b;
I kind of get the idea, it is sth like 1u - 2u is -1, but because both s1 and s2 are unsigned int, the result should also be unsigned int, therefore it overflow.
Not at all.
The result is whatever type you wish it to be, of course (it can be double for all I care), but that result type is not important - or at least it's not of primary importance, because it doesn't affect whether the operation itself is "OK" or not. The operation itself must be defined before you can even begin thinking about converting the result to any type at all (or leaving it in the "natural" type).
What you should focus on is whether an operation such as subtraction on two values of identical unsigned types is defined. And indeed, it always is defined. The C standard states what the result is - and it is very clear that there is no overflow. In fact, it's even clearer: the result can NEVER overflow:
A computation involving unsigned operands can never overflow, because a result that cannot be represented by the resulting unsigned integer type is reduced modulo the number that is one greater than the largest value that can be represented by the resulting type. (ISO/IEC 9899:1999 (E) §6.2.5/9)
Not only that, but conversions between integers and unsigned integers are well defined as well, and -1 (of type integer) converts to the maximum value of whatever unsigned type you convert it to. Basically, -1 converted to unsigned int is a short way of writing UINT_MAX etc.
unsigned char uc = -1;
assert(uc == UCHAR_MAX);
unsigned short us = -1;
assert(us == USHORT_MAX);
unsigned int ui = -1;
assert(ui == UINT_MAX);
unsigned long ul = -1;
assert(ul == ULONG_MAX);
// etc.
long long unsigned c= a* b;
since 1048577*4096 = 4294971392 which is out of range of int or unsigned b, so isn't that the result should overflow first?
The C language is simply not designed to interpret it the way you do. That's all. Most decisions in programming language design are completely arbitrary. You might be surprised of course that the designers made a decision different than you'd have made, but both are equally arbitrary.
What happens here is that the whole computation is performed using the long long unsigned type, and because it is an unsigned type, it never overflows. The C standard says so. And that's all there's to it.
One could argue that doing it the way you propose is worse, because there'd be way more typing to get something that should seem to work. If C worked the way you wanted, you'd need to write your expression as follows:
int a = 1048577;
size_t b = 4096;
long long unsigned c = (long long unsigned)a * (long long unsigned)b;
One could argue that forcing everyone to pollute their code with endless casts that way would be unkind to say the least. C is nicer than you expect it to be.
Of course C is also full of things that are abhorrent, so you were just lucky that you asked about this and not, say, the millionth question about why gets() is bad. The truth is: gets() is like Voldermort. You don't say gets and you don't use gets and everything is fine.

How can I confirm the range of unsigned long integer in C?

unsigned long has 8 bytes on my Linux gcc.
unsigned long long has 8 bytes on my Linux gcc, too.
So I think the range of integers they can show is from 0 min to (2^64 - 1)max.
Now I want to confirm if I'm correct.
Here is my code:
#include <stdio.h>
int main(void)
{
printf("long takes up %d bytes:\n", sizeof(long));
printf("long long takes up %d bytes:\n", sizeof(long long));
unsigned long a = 18446744073709551615;
a++;
printf("a + 1 = %lu\n", a);
unsigned long long b = 18446744073709551615;
b++;
printf("b + 1 = %llu\n", b);
return 0;
}
However, the code cannot be compiled and I get the following warning:
warning: integer constant is so large that it is unsigned
Where did I do wrong? How can I modify the code ?
When you initialize num, you can append the "UL" for unsigned long and ULL for unsigned long long.
For example:
unsigned long a = 18446744073709551615UL;
unsigned long long b = 18446744073709551615ULL;
Also, use %zu instead of %d because sizeof return size_t.
According to cppreference:
integer-suffix, if provided, may contain one or both of the following (if both are provided, they may appear in any order:
unsigned-suffix (the character u or the character U)
long-suffix (the
character l or the character L) or the long-long-suffix (the character
sequence ll or the character sequence LL) (since C99)
C standard 5.2.4.2.1 Sizes of integer types <limits.h> :
1 The values given below shall be replaced by constant expressions suitable for use in #if preprocessing directives. Moreover, except for
CHAR_BIT and MB_LEN_MAX, the following shall be replaced by
expressions that have the same type as would an expression that is an
object of the corresponding type converted according to the integer
promotions. Their implementation-defined values shall be equal or
greater in magnitude (absolute value) to those shown, with the same
sign.
You find some useful definitions in <limits.h>.
Initialize unsigned numbers with -1. This will automatically be MAX value in C.
#include <stdio.h>
int main(void)
{
printf("long takes up %d bytes:\n", sizeof(long));
printf("long long takes up %d bytes:\n", sizeof(long long));
unsigned long a = -1;
printf("a = %lu\n", a);
unsigned long long b = -1;
printf("b = %llu\n", b);
return 0;
}
Update: Changed the code based on comments :)
How can I confirm the range of unsigned long integer in C?
Best, just use the macros from <limits.h>. It better self documents code's intent.
unsigned long long b_max = ULLONG_MAX;
Alternatively, assign -1 to the unsigned type. As -1 is not in the range of an unsigned type, it will get converted to the target type by adding the MAX value of that type plus 1. The works even on rare machines that have padding.
... if the new type is unsigned, the value is converted by repeatedly adding or subtracting one more than the maximum value that can be represented in the new type until the value is in the range of the new type. C11dr §6.3.1.3 2
The min values is of course 0 for an unsigned type.
unsigned long long b_min = 0;
unsigned long long b_max = -1;
printf("unsigned long long range [%llu %llu]\n", b_min, b_max);
Note that picky compilers will complain about assigning an out-of-range value with b_max = -1;. Use ULLONG_MAX.
Where did I do wrong?
The warning "warning: integer constant is so large that it is unsigned" is due to 18446744073709551615 is a integer decimal constant outside the long long range on your platform. Unadorned decimal constants are limited to that. Append a U or u. Then the compiler will consider unsigned long long.
unsigned long long b = 18446744073709551615u;
Further, there is no C spec that says 18446744073709551615 is the max value of unsigned long long. It must be at least that. It could be larger. So assigning b = 18446744073709551615u may not assign the max value.
How can I modify the code ?
Shown above
As rsp stated you can specify the type of the literal with UL and ULL.
But this won't lead to a conclusive result in your code for the arithmetics.
The value your print will always be 0 because
2^64 % 64 = 0 // 64 = 8 byte
2^64 % 32 = 0 // 32 = 4 byte
2^64 % 16 = 0 // 16 = 2 byte
as you can see the variable size always doubles so if you us a wrapping number for 8 bytes it just wraps multiple types on the smaller sizes and yields the same result.
The sizeof will show you the right values.
But generally you want to check for these things in code and not on output so you could use limits.h as suggested by Arndt Jonasson.
or you can use static_assert to check at compile time.

Why do I get an integer overflow, and how do I fix it?

Trying to compile the following line in my code breaks:
printf("%llu\n", 0x12345678 * 0x12345678);
I get this:
program.c:45:34: warning: integer overflow in expression [-Woverflow]
printf("%llu\n", (0x12345678 * 0x12345678));
How do I fix this?
[After accept correction per #Lundin] comment
On your machine, 0x12345678 is narrower than unsigned long long - certainly a signed long or maybe int.
A signed long * signed long is still an signed long and can suffer from signed integer overflow, which is UB. The range of your signed long is less than the mathematical product of 0x12345678 * 0x12345678. By using ULL suffix, the math is done at least with unsigned long long math. #BLUEPIXY
printf("%llu\n", 0x12345678ULL * 0x12345678);
// or if the constant can not be changed
printf("%llu\n", 1ULL * SOME_BIG_CONSTANT * SOME_BIG_CONSTANT);
Pedantic note: When printing integer types that might wider than int/unsigned, insure the final computed result matches the specifier. Consider that SOME_BIG_CONSTANT might be wider than unsigned long long. Or leave the cast off, and cope with the potential compiler warning.
printf("%llu\n", (unsigned long long) (1ULL * SOME_BIG_CONSTANT * SOME_BIG_CONSTANT));
See also Why write 1,000,000,000 as 1000*1000*1000 in C?
and There are reasons not to use 1000 * 1000 * 1000

Wrong answer in C for long number calculations

long int k=(long int)(2000*2000*2000);
the above calculation is giving me wrong answer in C. What is wrong?
If a C integer constant fits in an int, it is of type int. So your expression is evaluated as:
long int k = (long int)((int)2000*(int)2000*(int)2000);
If int isn't large enough to hold the result of the multiplication, you'll get a signed integer overflow and undefined behavior. So if long is large enough to hold the result, you should write:
long k = 2000L * 2000L * 2000L;
The L suffix forces the type of the literal to long (long is equivalent to long int).
But on most platforms, even long is only a 32-bit type, so you have to use long long which is guaranteed to have at least 64 bits:
long long k = 2000LL * 2000LL * 2000LL;
The LL suffix forces the type of the literal to long long.
2000 is of type int, so 2000*2000*2000 is also of type int.
Assuming a 32-bit int (which is actually more than the standard requires, since an int is not required by the standard to represent a value more than 32767) the maximum representable value is about 2,147,483,647 (commas inserted for readability) which is less than 8,000,000,000.
You will probably want to do the calcuation as 2000LL*2000*2000 which takes advantage of multiplication being left-right associative, and will promote all the 2000 values to long long int before doing the multiplication. Your variable will also need to be of type long long int if you want a guarantee of being able to store the result.
Holt's answer is the correct one, I am just leaving this here as caveat!
You could try to use:
long long int
instead of
long int
However, in my local machine, it has no effect:
#include <stdio.h>
int main(void)
{
long int k=(long int)(2000*2000*2000);
printf("With long int, I am getting: %ld\n", k);
long long int n = 2000*2000*2000;
printf("With long long int, I am getting: %lld\n", n);
return 0;
}
Output:
With long int, I am getting: -589934592
With long long int, I am getting: -589934592
Warnings:
../main.c:6:36: warning: integer overflow in expression [-Woverflow]
long int k=(long int)(2000*2000*2000);
^
../main.c:9:32: warning: integer overflow in expression [-Woverflow]
long long int n = 2000*2000*2000;
Even this:
unsigned long long int n = 2000*2000*2000;
printf("With long long int, I am getting: %llu\n", n);
will overflow too.
There are two problems in your code:
long int is (on most architecture) not enough to store 8e9.
When you do 2000 * 2000 * 2000, operations are made using "simple" int, thus, int * int * int = int so you cast the result to an int and then to a long int.
You need to use long long int and specify that you want long long int:
long long int k = 2000LL*2000LL*2000LL;
Notice the extra LL after 2000 saying "It's 2000, but as a long long int!".
You can't just multiply the values together as ordinary precision integers and then cast the result to a higher precision, because the result has already overflowed at that point. Instead, the operands need to be higher precision integers before they're multiplied. Try the following:
#include <stdio.h>
int main(void)
{
long long int n = (long long int)2000*(long long int)2000*(long long int)2000;
printf("long long int operands: %lld\n", n);
return 0;
}
On my machine, this gives:
long long int operands: 8000000000

long long int initialization warnings

2 Questions
First, while
long long int num = 1000000000000;
works fine
long long int num = 4014109449;
gives
warning: this decimal constant is unsigned only in ISO C90 [enabled by default]
What does it mean ?
Secondly
long long int num = 1000000*1000000;
gives an overflow warning
while
long long int num = 1000000000000;
is ok,even though they are same.How do i get rid of it? Multiplication gives a garbage value
The problem is that the value 4014109449 is an unsigned long int in C90 but a long long int in C99 because it is too large for a 32-bit long int. While 1000000000000 is too large for any 32-bit type, so is automatically a long long int. The warning relates to the fact that the behaviour differs between C90 and C99.
The solution is to force type agreement between the literal and the variable type by using an appropriate type suffix. In this case:
long long num = 4014109449LL ;
or use a type cast:
long long num = (long long)4014109449 ;
Similarly the expression 1000000 * 1000000 is a multiply of two int types and has an int result, but causes an overflow - there is no automatic promotion to a larger type for int expressions. The solution is again to be explicit about the type of the literal:
long long num = 1000000LL * 1000000LL;
or you can also use a type cast on one or both operands.
long long num = (long long)1000000 * 1000000;
In C90, the type of an unsuffixed decimal integer constant (literal) is the first of
int
long int
unsigned long int
that can represent its value without overflow.
In C99 and later, it's the first of
int
long int
long long int
that can represent its value.
The value 4014109449 happens to be representable as a 32-bit unsigned integer, but not as a 32-bit signed integer. Assuming your system has 32-bit longs, that constant's type is unsigned long int in C90, long long int in C99 and C11.
That's what the warning is telling you. The type of the constant changes depending on which version of the C standard your compiler conforms to.
Note that, regardless of its type, the value of 4014109449 will always be correct, and in your declaration:
long long int num = 1000000000000;
that value will always be correctly converted to long long. But it certainly wouldn't hurt (and would silence the warning) to add a LL suffix to make it explicit that you want a value of type long long:
long long int num = 1000000000000LL;
As for this:
long long int num = 1000000*1000000;
assuming you have 32-bit ints, the constant 1000000 is of type int, and the result of multiplying two int values is also of type int. In this case, the multiplication will overflow. Again, you can avoid the problem by ensuring that the constants are of type long long int:
long long int num = 1000000LL * 1000000LL;
(Note that you can use lowercase ll, but it's a bad idea, since it can be difficult to distinguish the letter l from the digit 1.)

Resources