I am writing a program in C to calculate the range of different data types. Please look at the following code:
#include <stdio.h>
main()
{
int a;
long b;
for (a = 0; a <= 0; --a)
;
++a;
printf("INT_MIN: %d\n", a);
for (a = 0; a >= 0; ++a)
;
--a;
printf("INT_MAX: %d\n", a);
for (b = 0; b <= 0; --b)
;
++b;
printf("LONG_MIN: %d\n", b);
for (b = 0; b >= 0; ++b)
;
--b;
printf("LONG_MAX: %d\n", b);
}
The output was:
INT_MIN: -32768
INT_MIN: 32767
LONG_MIN: 0
LONT_MAX: -1
The program took a long pause to print the long values. I also put a printf inside the third loop to test the program (not mentioned here). I found that b did not exit the loop even when it became positive.
I used the same method of calculation. Why did it work for int but not for long?
You are using the wrong format specifier. Since b is of type long, use
printf("LONG_MIN: %ld\n", b);
In fact, if you enabled all warnings, the compiler probably would warn you, e.g:
t.c:19:30: warning: format specifies type 'int' but the argument has type 'long' [-Wformat]
printf("LONG_MIN: %d\n", b);
In C it is undefined behaviour to decrement a signed integer beyond its minimum value (and similiarly for incrementing above the maximum value). Your program could do literally anything.
For example, gcc compiles your program to an infinite loop with no output.
The proper approach is:
#include <limits.h>
#include <stdio.h>
int main()
{
printf("INT_MIN = %d\n", INT_MIN);
// etc.
}
In
printf("LONG_MIN: %d\n", b);
the format specifier is %d which works for integers(int). It should be changed to %ld to print long integers(long) and so is the case with
printf("LONG_MAX: %d\n", b);
These statements should be
printf("LONG_MIN: %ld\n", b);
&
printf("LONG_MAX: %ld\n", b);
This approach may not work for all compilers(eg gcc) and an easier approach would be to use limits.h.
Also check Integer Limits.
As already stated, the code you provided invokes undefined behavior. Thus it could calculate what you want or launch nuclear missiles ...
The reason for the undefined behavior is the signed integer overflow that you are provoking in order to "test" the range of the data types.
If you just want to know the range of int, long and friends, then limits.h is the place to look for. But if you really want ...
[..] to calculate the range [..]
... for what ever reason, then you could do so with the unsigned variant of the respective type (though see the note at the end), and calculate the maximum like so:
unsigned long calculate_max_ulong(void) {
unsigned long follow = 0;
unsigned long lead = 1;
while (lead != 0) {
++lead;
++follow;
}
return follow;
}
This only results in an unsigned integer wrap (from the max value to 0), which is not classified as undefined behavior. With the result from above, you can get the minimum and maximum of the corresponding signed type like so:
assert(sizeof(long) == sizeof(unsigned long));
unsigned long umax_h = calculate_max_ulong() / 2u;
long max = umax_h;
long min = - max - 1;
(Ideone link)
Assuming two's complement for signed and that the unsigned type has only one value bit more than the signed type. See ยง6.2.6.2/2 (N1570, for example) for further information.
Related
Beginner in C language.
I suspect it may be due to overflow, but could not solve this simple exercise:
program to compute the sum of squares of all the natural numbers smaller than 10000
I initially tried:
#include <stdio.h>
int main() {
int a = 10000;
int square(int num) {
return num * num;
};
int total = 0;
while (a > 0) {
a--;
total += square(a);
//printf("a is %d and square is %d and total %d \n", a, square(a), total );
};
printf("total is %d ", total );
return total;
}
result: total is -1724114088
and here there's the strange thing:
...
a is 9936 and square is 98724096 and total 2063522144
a is 9935 and square is 98704225 and total -2132740927
...
So I tried to change total to long, tried to change declaring square function as long square(int num ), but nothing changed.
Could you explain why the sum turns negative ?
Is it due to overflow ? But why not resetting to 0 or positive, instead of going negative ?
how can I know how many bits for int are there in a computer that I don't know (e.g. cloud ?
E.g. I am coding here: [https://www.programiz.com/c-programming/online-compiler/]
Which is best practice to fix it ?
Do not define function in functions.
int main() {
int square() { // NO!
Functions belong at file scope:
int square() { //OK
}
int main() { //OK
}
The code compiles because compilers have extensions to the language. It's not part of the C programming language.
Could you explain why the sum turns negative ?
See ex. why the value of sum is coming out to be negative? and other questions. The sum "wraps around" on your platform.
Is it due to overflow ?
Yes.
But why not resetting to 0 or positive, instead of going negative ?
Because systems nowadays are twos-complement, it's simpler to implement a single hardware instruction for adding numbers then two separate instructions with special overflow semantics. Unsigned and signed twos-complement numbers behave the same when doing operations on them, so instead of doing special semantics on overflow, when adding signed numbers they are added the same as they would be unsigned (bits are just added) and the result is then interpreted as a signed number (in a C program), which because the most significant bit becomes set the number becomes negative.
Anyway, compiler just does not care, because signed overflow is undefined behavior compiler does not have to care. The compiler just generates a hardware instruction for signed addition, which behaves as explained above.
how can I know how many bits for int are there in a computer that I don't know
You can check your compiler documentation.
But usually it's simpler to just compile a simple C program where you use CHAR_BIT - the number of bits in a byte - and sizeof(int) - the number of bytes in an int - and inspect the output of that program. For example, a program such as:
#include <stdio.h>
#include <limits.h>
int main() {
printf("There are %d bits in int\n", (int)sizeof(int) * CHAR_BIT);
}
Note that number of bits in types does not only change with platform and operating systems, it can change with compiler, compiler versions and also compilation options.
Which is best practice to fix it ?
This depends on what behavior do you want.
To calculate bigger values use a bigger datatype - long or long long. When the language features are not enough, move your program to use some big number library.
If you want to terminate the program in case of problems - you can check for overflow and call abort() or similar if it happens.
Instead, you could have used a formula.
Sum of Squares of first N natural numbers = (N * (N + 1) * (2 * N + 1) / 6
For now, let N be 10000.
Ignoring the 6 in the formula, the sum of squares is as big as 10^12. It will not fit in an integer. You should use a data type that can accommodate bigger values, like long or long long int.
Here's the modified code.
#include <stdio.h>
int main() {
int a = 10000;
int square(int num) {
return num * num;
};
// Change int to long long int
long long int total = 0;
while (a > 0) {
a--;
total += square(a);
//printf("a is %d and square is %d and total %d \n", a, square(a), total );
};
// Change %d to %lld
printf("total is %lld ", total );
return total;
}
You'll need to change all uses of int to long:
#include <stdio.h>
int main() {
long a = 10000;
long square(long num) {
return num * num;
};
long total = 0;
while (a > 0) {
a--;
total += square(a);
//printf("a is %ld and square is %ld and total %ld \n", a, square(a), total );
};
printf("total is %ld ", total );
return 0;
}
which prints total is 333283335000
EDIT
Or you could just change the total, the return type of square, and perform the appropriate casts when computing the squared values:
#include <stdio.h>
int main() {
int a = 10000;
long square(int num) {
return (long)num * (long)num;
};
long total = 0;
while (a > 0) {
a--;
total += square(a);
//printf("a is %ld and square is %ld and total %ld \n", a, square(a), total );
};
printf("total is %ld ", total );
return 0;
}
Produces the same result shown above.
onlinegdb here
I know the solution is ugly and technically incorrect but I don't understand why the code doesn't work.
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
int main (int argc, char *argv[]) {
int u;
scanf("%d", &u);
printf("absValue = %u\n", u);
return 0;
}
%u specifies an unsigned decimal character but when I input a negative value, it gives
absValue = 4294967293
Alternatively, with the if command, how to convert the negative sign to positive?
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
int main (int argc, char *argv[]) {
int n;
scanf("%d", &n);
if(n < 0) {
printf("absValue = -%d\n", n);
} else {
printf("absValue = %d\n", n);
}
return 0;
}
The shortest solution in your first piece of code is to change the printf statement as follows:
printf("absValue = %u\n", (unsigned)((u<0)?-u:u));
This will print the absolute value of u. The type conversion (unsigned) ensures that the data type is as expected by printf. The statement (u<0)?-u:u uses the conditional operator to select the value -u if the condition (u<0) is true and u if the condition is false (i.e. u>=0).
The problem in your code is that u is a signed integer which means its value is stored using the Two's complement representation in 4 bytes(*) and printf is not intelligent. When you tell printf to display an unsigned integer, then printf will take the 4 bytes holding u and interpret them as an unsigned integer. Since negative numbers in Two's complement are stored as large positive integers, that is the result you see.
(*) The use of Two's complement and the int size of 4 is machine-dependent, but common.
As an alternative, you can also use the standard C function abs() (or one of its related functions):
7.22.6.1 The abs, labs and llabs functions
Synopsis
#include <stdlib.h>
int abs(int j);
long int labs(long int j);
long long int llabs(long long int j);
Description
The abs, labs, and llabs functions compute the absolute value of
an integer j. If the result cannot be represented, the behavior is
undefined.
Returns
The abs, labs, and llabs, functions return the absolute value.
Footnotes
The absolute value of the most negative number cannot be represented
in two's complement.
Note the footnote "The absolute value of the most negative number cannot be represented in two's complement." and "If the result cannot be represented, the behavior is undefined." Strictly speaking, you'd likely need to use long long int and llabs() to avoid undefined behavior in converting INT_MIN to a positive value, assuming a 32-bit int value, and long is often 32-bits, even on 64-bit Windows.
However, since double values are likely implemented in IEEE format with 53 bits of precision, a 32-bit int value can be converted to double with no loss of precision, so you can use the fabs() function to get the absolute value of a 32-bit int value in one call:
7.12.7.2 The fabs functions
Synopsis
#include <math.h>
double fabs(double x);
float fabsf(float x);
long double fabsl(long double x);
The fabs functions compute the absolute value of a floating-point
number x.
So your code would be:
#include <stdio.h>
#include <math.h>
int main (int argc, char *argv[]) {
int u;
scanf("%d", &u);
printf("absValue = %u\n", (unsigned) fabs((double) u));
return 0;
}
Note that in (unsigned) fabs((double) u), casting u to double is not strictly necessary, as the int value will be implicitly converted to a double because of the double fabs(double) function prototype from stdlib.h. But the cast back to unsigned is exremely necessary to pass the unsigned int value you want to pass to printf().
You could also do this:
#include <stdio.h>
#include <math.h>
int main (int argc, char *argv[]) {
int u;
scanf("%d", &u);
unsigned int absValue = fabs(u);
printf("absValue = %u\n", absValue);
return 0;
}
That works because unsigned int absValue is explicitly an unsigned int.
Also, on modern CPUs, conversion between int and double is usually done by a single relatively fast instruction.
How to write absolute value in c?
The shortest solution :
#include <stdlib.h>
printf("absValue = %d\n", abs(u)); // clear and concise - yet see below
Both printf("%d\n", abs(u)); and printf("%u\n", (unsigned)((u<0)?-u:u)); suffer the same problem: undefined behavior (UB) when n == INT_MIN1. The signed negation of INT_MIN is the UB.
At least abs(u) is clear, unlike (unsigned)((u<0)?-u:u).
To print the absolute value of an int, code could negate negative values with:
(-1 - n) + 1u or
-(unsigned)n or
0u - n
... and end up with an unsigned.2
I'd go for the simplest when a full range |int| is sought.
printf("absValue = %u\n", n < 0 ? 0u - n : (unsigned) n);
Using long, long long or double poses their own troubles and portability. None warranted here.
1 when int is 2's complement encoded - very common.
2 C specified UINT_MAX >= INT_MAX. In the very rare implementations today, INT_MAX == INT_MAX is possible and code needs to resort to a wider type when int is non 2's complement.
printf doesn't convert the strings, but rather expects them converted. I would generally prefer to use the standard abs function which is declared in stdlib.h. This uses strtol to convert an argument to a long then convert that to an int. Nota bene, that, for example, if your machine uses two's-complements, calling abs(INT_MIN) produces undefined behaviour and should be dealt with. (Edited: error detection now complies with non-POSIX systems; see comments.)
#include <stdio.h> /* perror, printf */
#include <stdlib.h> /* strtol, abs */
#include <limits.h> /* INT_MIN, INT_MAX */
#include <errno.h> /* errno, ERANGE */
int main(int argc, char *argv[]) {
int u;
long input;
char *end;
/* Require one argument. */
if(argc != 2) return printf("Usage <number>\n"), EXIT_SUCCESS;
/* `input` is converted from `argv[1]`, if it's 0, check that it actually
read 0; check to see garbage characters at the end; check to see if the
`input` is a) less then `INT_MIN`; b) also if `-INT_MAX < 0`, check that
it is not lower than this value, because that will lead to undefined
`abs`; c) more then `INT_MAX` -> if so, set `ERRNO` and enter the if. */
if( ((input = strtol(argv[1], &end, 0)) == 0 && end == argv[1])
|| (*end != '\0' && (errno = EILSEQ, 1))
|| ((input < INT_MIN || (-INT_MAX < 0 && input < -INT_MAX)
|| input > INT_MAX) && (errno = ERANGE, 1)) )
return perror("Input"), EXIT_FAILURE;
/* We are pretty sure this cast is safe, now: `int abs(int)`. */
u = abs((int)input);
printf("absValue(%ld) = %d\n", input, u);
return EXIT_SUCCESS;
}
Checking edge cases,
bin/abs 2147483647
absValue(2147483647) = 2147483647
bin/abs 2147483648
Input: Result too large
bin/abs -2147483648
Input: Result too large
bin/abs -2147483647
absValue(-2147483647) = 2147483647
bin/abs
Usage <number>
bin/abs 0x10
absValue(16) = 16
bin/abs asdf
Input: Invalid argument
bin/abs 1a
Input: Illegal byte sequence
this is a function to get the absolute value of a number without using abs() function.
int abs_value(int *a){
return *a < 0 ? -*a: *a;
}
If you want to get the absolute difference between two numbers, here's how:
int abs_diff (int *a, int*b) {
return *a > *b ? *a - *b : *b - *a;
}
I was working on Exercise 2-1 of K&R, the goal is to calculate the range of different variable types, bellow is my function to calculate the maximum value a short int can contain:
short int max_short(void) {
short int i = 1, j = 0, k = 0;
while (i > k) {
k = i;
if (((short int)2 * i) > (short int)0)
i *= 2;
else {
j = i;
while (i + j <= (short int)0)
j /= 2;
i += j;
}
}
return i;
}
My problem is that the returned value by this function is: -32768 which is obviously wrong since I'm expecting a positive value. I can't figure out where the problem is, I used the same function (with changes in the variables types) to calculate the maximum value an int can contain and it worked...
I though the problem could be caused by comparison inside the if and while statements, hence the typecasting but that didn't help...
Any ideas what is causing this ? Thanks in advance!
EDIT: Thanks to Antti Haapala for his explanations, the overflow to the sign bit results in undefined behavior NOT in negative values.
You can't use calculations like this to deduce the range of signed integers, because signed integer overflow has undefined behaviour, and narrowing conversion at best results in an implementation-defined value, or a signal being raised. The proper solution is to just use SHRT_MAX, INT_MAX ... of <limits.h>. Deducing the maximum value of signed integers via arithmetic is a trick question in standardized C language, and has been so ever since the first standard was published in 1989.
Note that the original edition of K&R predates the standardization of C by 11 years, and even the 2nd one - the "ANSI-C" version predates the finalized standard and differs from it somewhat - they were written for a language that wasn't almost, but not quite, entirely unlike the C language of this day.
You can do it easily for unsigned integers though:
unsigned int i = -1;
// i now holds the maximum value of `unsigned int`.
Per definition, you cannot calculate the maximum value of a type in C, by using variables of that very same type. It simply doesn't make any sense. The type will overflow when it goes "over the top". In case of signed integer overflow, the behavior is undefined, meaning you will get a major bug if you attempt it.
The correct way to do this is to simply check SHRT_MAX from limits.h.
An alternative, somewhat more questionable way would be to create the maximum of an unsigned short and then divide that by 2. We can create the maximum by taking the bitwise inversion of the value 0.
#include <stdio.h>
#include <limits.h>
int main()
{
printf("%hd\n", SHRT_MAX); // best way
unsigned short ushort_max = ~0u;
short short_max = ushort_max / 2;
printf("%hd\n", short_max);
return 0;
}
One note about your code:
Casts such as ((short int)2*i)>(short int)0 are completely superfluous. Most binary operators in C such as * and > implement something called "the usual arithmetic conversions", which is a way to implicitly convert and balance types of an expression. These implicit conversion rules will silently make both of the operands type int despite your casts.
You forgot to cast to short int during comparison
OK, here I assume that the computer would handle integer overflow behavior by changing into negative integers, as I believe that you have assumed in writing this program.
code that outputs 32767:
#include <stdlib.h>
#include <stdio.h>
#include <malloc.h>
short int max_short(void)
{
short int i = 1, j = 0, k = 0;
while (i>k)
{
k = i;
if (((short int)(2 * i))>(short int)0)
i *= 2;
else
{
j = i;
while ((short int)(i + j) <= (short int)0)
j /= 2;
i += j;
}
}
return i;
}
int main() {
printf("%d", max_short());
while (1);
}
added 2 casts
I am newbie, please bear if my question is silly.
int main()
{
int x=60674;
printf("%lf \n",(double)(x*x));
printf("%lld \n",(long long)(x*x));
return 0;
}
Why is this not working?
x * x overflows, so you should cast them into long longs before the multiplication:
printf("%lld \n",((long long)x * (long long)x));
Additionaly you may use standardised ints:
#include <inttypes.h>
#include <stdio.h>
int main() {
int x=60674;
printf("%" PRIu64 "\n",(uint64_t)x * x);
return 0;
}
Moreover you do not need to cast both variables .. the * will impose using the bigger type of the two multipliers.
Btw you could just use unsigned int .. the result would fit in UINT_MAX which is 4294967295 (from here )
x is a signed integer that can hold value only upto -2,147,483,847 to +2,147,483,847 and on performing the operation
x * x
==> 60674 * 60674 = 3,681,334,276
which generally overflows the integer range. Hence you might need some big data type to hold that calculation 60674 * 60674
You can try two things to do that.
Change the data type of x from int to long or for more range long long
long long x = 60674;
Type cast the calculation to long range data type.
printf("%lld \n",((long long)x* (long long)x));
At the iteration for calculating the factorial for 13 it starts to produce invalid results. I have typed this up exactly the way it is written in my textbook but I am getting a different output then what is listed in the book. My compiler is Dev C++ and its set to the C99 standard. Is there some setting that is off in the compiler that would cause unsigned long long ints to not format correctly or not have the appropriate max value? At 13! it prints 1932053504.
#include <stdio.h>
//prototype for factorial function
unsigned long long int factorial(unsigned int number);
int main(void){
unsigned int i; //counter for for-loop
//during each iteration call factorial and print result
for( i = 0; i <= 21; ++i){
printf("%u! = %11u\n", i, factorial(i));
}
}
unsigned long long int factorial(unsigned int number){
if(number <= 1){
return 1;
}
else{ //recursive step
return(number * factorial(number - 1));
}
}
I think you have a typo in your specifier. I think you meant ll not 11. You're passing a unsigned long long to it so it needs to be
printf("%u! = %llu\n", i, factorial(i));
This is another reason to turn on (and pay attention to) compiler warnings. My compiler told me straight away what the problem was.
test.c:11:35: warning: format specifies type 'unsigned int' but the argument has type 'unsigned long long' [-Wformat]
printf("%u! = %11u\n", i, factorial(i));
~~~~ ^~~~~~~~~~~~
%11llu
1 warning generated.
The answer you've been getting is the result of undefined behavior but your machine being little endian, having 32 bit ints, 13! = 6227020800 > 2^32 = 4294967296 and that 6227020800 % 4294967296 = 1932053504 may have been the reasons why you were getting that answer.