Weird negative number after % operation - c

So I have something like the following,
int main()
{
int a[10];
int i=0;
int n=10000000000;
while (n!=0)
{
a[i++]=n%10;
printf("we have n is %d\n", n);
printf("we have n mod 10 is %d\n", n%10);
n/=10;
printf("we have%d\n", a[i]);
}
Somehow I would always get a negative number when the n mod 10 is '0‘, can someone tell me why?

int is too small to hold that number. You are getting an overflow which is causing n to actually be a negative number, so you get a negative value for the modulo operation.

The number is well past the limit of int on positive side.
You can run following codes to know the limits on integers in your OS
C:
#include <limits.h>
const int min_int = INT_MIN;
const int max_int = INT_MAX;
C++:
#include <limits>
const int min_int = std::numeric_limits<int>::min();
const int max_int = std::numeric_limits<int>::max();
What you need to do:
Choose another data type like double. You can also choose something like long int or simply long or size_t or int64_t which are each at least 64 bits.
For comparison:
signed int: -32767 to 32767
unsigned int: 0 to 65535
signed long:-2147483647 to 2147483647
unsigned long: 0 to 4294967295
Why negative?
The negative number happens because a typical signed int lies between -32767 to 32767
and then 32767 is represented as overflow. So this will be a negative number after truncating the overflow.
Also note that the sizeof a type is determined by the compiler,
which doesn't have to have anything to do with the actual hardware
(though it typically does); in fact, different compilers on the same
machine can have different values for these.

Related

Unable to calculate factorial , getting output as 0 in C

Tried calculating factorial of 65, got correct output. Anything greater than 65 results in output of 0. Shocking since I'm using unsigned long int. What is amiss ?
Code:
#include <stdio.h>
void factorial(int unsigned long);
int main()
{
int unsigned long num, result;
printf("\nEnter number to obtain factorial : ");
scanf("%ld", &num);
factorial(num);
}
void factorial (int unsigned long x)
{
register int unsigned long f = 1;
register int unsigned long i;
for (i=x;i>=1;i--)
f= f*i;
printf("\nFactorial of %lu = %lu\n",x,f);
}
You certainly did not get the correct result for 65! log2(65!) is just over 302 bits (Google it), so you'd need a long int of at least 303 bits to calculate that correctly. There is no computer in the world where long int is over 300 bits (let's see how this answer ages!).
The largest factorial you can compute in 64 bits is 20! (which is about 2.4e18).
Adding on to #JohnZwinck, the maximum value for a variable of type unsigned long long (ULLONG_MAX) is 18446744073709551615. So all the values greater than 20! are going to have a garbage value
You can refer to this for more information.

Using an unsigned int in a do-while loop

I'm new to coding in c and I've been trying to wrap my head around unsigned integers. This is the code I have:
#include <stdio.h>
int main(void)
{
unsigned int hours;
do
{
printf("Number of hours you spend sleeping a day: ");
scanf(" %u", &hours);
}
while(hours < 0);
printf("\nYour number is %u", hours);
}
However, when I run the code and use (-1) it does not ask the question again like it should and prints out (Your number is 4294967295) instead. If I change unsigned int to a normal int, the code works fine. Is there a way I can change my code to make the unsigned int work?
Appreciate any help!
Is there a way I can change my code to make the unsigned int work?
Various approaches possible.
Read as int and then convert to unsigned.
Given "Number of hours you spend sleeping a day: " implies a small legitimate range about 0 to 24, read as int and convert.
int input;
do {
puts("Number of hours you spend sleeping a day:");
if (scanf("%d", &input) != 1) {
Handle_non_text_input(); // TBD code for non-numeric input like "abc"
}
} while (input < 0 || input > 24);
unsigned hours = input;
An unsigned int cannot hold negative numbers. It is useful since it can store a full 32 bit number (twice as large as a regular int), but it cannot hold negative numbers So when you try to read your negative unsigned int, it is being read as a positive number. Although both int and unsigned int are 32 bit numbers, they will be interpreted much differently.
I would try the next test:
do:{
printf("enter valid input...")
scanf("new input...")
} while (hours > 24)
Why should it work?
An unsigned int in C is a binary number, with 32 bit. that means it's max value is 2^32 - 1.
Note that:
2^32 - 1 == 4294967295. That is no coincidence. Negative ints are usually represented using the "Two's complement" method.
A word about that method:
When I use a regular int, it's most significant bit is reserved for sign: 1 if negative, 0 if positive. A positive int than holds a 0 in it's most significant bit, and 1's and 0's on the remaining coordinates in the ordinary binary manner.
Negative ints, are represented differently:
Suppose K is a positive number, represented by N bits.
The number (-K) is represented using 1 in the most significant bit, and the POSITIVE NUMBER: (2^(N-1) - K) occupying the N-1 least significant bits.
Example:
Suppose N = 4, K = 7. Binary representation for 7 using 4 bit:
7 = 0111 (The most significant bit is reserved for sign, remember?)
-7 , on the other hand:
-7 = concat(1, 2^(4-1) - 7) == 1001
Another example:
1 = 0001, -1 = 1111.
Note that if we use 32 bits, -1 is 1...1 (altogether we have 32 1's). This is exactly the binary representation of the unsigned int 4294967295. When you use unsigned int, you instruct the compiler to refer to -1 as a positive number. This is where your unexpected "error" comes from.
Now - If you use the while(hours>24), you rule out most of the illegal input. I am not sure though if you rule out all illegal input. It might be possible to think of a negative number such that the compiler interpret it as a non-negative number in the range [0:24] when asked to ignore the sign, and refer to the most significant bit as 'just another bit'.

Pow is not working for two double digit numbers

I have made a code to read two long integers (A and B) from standard input and output (to standard output) A to the power of B.
It works for 1^some huge number, 3^3 etc.
But not for 13^16.
I've tried to put long int ans to solve it, it gave me a different value but not the right one.
#include <stdio.h>
#include <math.h>
int main()
{
int x, n;
long int ans;
scanf("%d \n %d",&x, &n);
ans = pow(x,n);
printf("%d", ans);
return 0;
}
pow(1,anything) is always 1. pow(3, 3) is 27. These are both quite small numbers and easily fit into a 32 bit integer. pow(13,16) is (approximately) 6.65 x 1017. This is too big for a 32 bit integer to contain. It will go into a 64 bit integer (although pow(14, 17) will not). It's likely that your compiler treats a long as a 32 bit value, which is not uncommon. You could try long long which is likely to be 64 bits or int64_t which is explicitly 64 bits long.
Note though that the prototype for pow() is
double pow(double x, double y);
which means that it is returning a double precision floating point number and then coercing it into the type of your variable. double (a 64 bit floating point number) only has 53 bits of precision in its mantissa, which means you are not going to get the exact number when you cast it back to even a 64 bit integer. You could use powl() whose prototype is
long double powl(long double x, long double y);
But long double might be defined as 80 bits or 128 bits or even only 64 bits (Microsoft). It might give you the precision you need, but such is the nature of power operations, your input numbers won't have to get much bigger to overflow the precision of even the longest long double.
If you really need to raise large numbers to large powers, you are going to need a big integer library.
Rather than use floating point pow() and friends with their potential limited precision for an integer problem within 64 bits (1316 needs 60 bits), use an integer power function.
unsigned long long upow(unsigned x, unsigned y) {
unsigned long long z = 1;
unsigned long long xx = x;
while (y) {
if (y % 2) {
z *= xx;
}
y /= 2;
xx *= xx;
}
return z;
}
int main() {
printf("%llu\n", upow(3, 3));
printf("%llu\n", upow(13, 16));
}
Output
27
665416609183179841
If code needs to handle answers more the 64 bits, consider long double (with potential loss of precision) or big_integer libraries.
You have defined "ans" as long int then you are trying to print it as int (%d - Take the next argument and print it as an int ) So change printf("%d", ans) to printf("%ld",ans) . your code would look something like this :
#include <stdio.h>
#include <math.h>
int main()
{
int x, n;
long int ans;
scanf("%d \n %d",&x, &n);
ans = pow(x,n);
printf("%ld", ans);
return 0;
}

Using unsigned data types in C

How to use unsigned int properly? My function unsigned int sub(int num1, int num2);doesn't work when user input a is less than b. If I simply use int, we can expect a negative answer and I need to determine which is larger before subtracting. I know that's easy but maybe there is a way to use unsigned int to avoid that?
For instance when a = 7 and b = 4, the answer is 3.000000. But when I flip them, the code gives me 4294967296.000000 which I think is a memory address.
#include <stdio.h>
unsigned int sub(int num1,int num2){
unsigned int diff = 0;
diff = num1 - num2;
return diff;
}
int main(){
printf("sub(7,4) = %u\n", sub(7,4));
printf("sub(4,7) = %u\n", sub(4,7));
}
output:
sub(7,4) = 3
sub(4,7) = 4294967293
Unsigned numbers are unsigned... This means that they cannot be negative.
Instead they wrap (underflow or overflow).
If you do an experiment with an 8-bit unsigned, then you can see the effect of subtracting 1 from 0:
#include <stdio.h>
#include <stdint.h>
int main(void) {
uint8_t i;
i = 1;
printf("i: %hhu\n", i);
i -= 1;
printf("i: %hhu\n", i);
i -= 1;
printf("i: %hhu\n", i);
return 0;
}
i: 1
i: 0
i: 255
255 is the largest value that an 8-bit unsigned can hold (2^8 - 1).
We can then do the same experiment with a 32-bit unsigned, using your 4 - 7:
#include <stdio.h>
#include <stdint.h>
int main(void) {
uint32_t i;
i = 4;
printf("i: %u\n", i);
i -= 7;
printf("i: %u\n", i);
return 0;
}
i: 4
i: 4294967293
4294967293 is effectively 0 - 3, which wraps to 2^32 - 3.
You also need to be careful of assigning an integer value (the return type of your sub() function) to a float... Generally this is something to avoid.
See below. x() returns 4294967293 as an unsigned int, but it is stored in a float... This float is then printed as 4294967296???
#include <stdio.h>
#include <stdint.h>
unsigned int x(void) {
return 4294967293U;
}
int main(void) {
float y;
y = x();
printf("y: %f\n", y);
return 0;
}
y: 4294967296.000000
This is actually to do with the precision of float... it is impossible to store the absolute value 4294967293 in a float.
What you see is called unsigned integer overflow. As you noted, unsigned integers can't hold negative numbers. So when you try to do something that would result in a negative number, seemingly weird things can occour.
If you work with 32-bit integers,
int (int32_t) can hold numbers between (-2^31) and (+2^31-1), INT_MIN and INT_MAX
unsigned int (uint32_t) can hold numbers between (0) and (2^32-1), UINT_MIN and UINT_MAX
When you try to add something to an int that would lead to a number greater than the type can hold, it will overflow.
unsigned int cannot be used to represent a negative variable. I believe what you wanted is to find the absolute value of the difference between a and b. If so, you can use the abs() function from stdlib.h. The abs() function takes in an int variable i and returns the absolute value of i.
The reason why unsigned int returns a huge number in your case is due to the way integers are represented in the system. You declared diff as an int type, which is capable of storing a negative value, but the same sequence of bits that represents -3 when interpreted as unsigned int represents 4294967296 instead.
It becomes a negative number, unsigned data types dont hold negative number, so instead it becomes a large number
"absolute value of the difference between a and b" does not work for many combinations of a,b. Any a-b that overflows is undefined behavior. Obviously abs(INT_MAX - INT_MIN) will not generate the correct answer.
Also, using abs() invokes undefined behavior with a select value of int. abs(INT_MIN) is undefined behavior when -INT_MIN is not representable as an int.
To calculate the absolute value difference of 2 int, subtract them as unsigned.
unsigned int abssub(int num1,int num2){
return (num1 > num2) ? (unsigned) num1 - num2 : (unsigned) num2 - num1;
}

Weird Question regarding C integer type and printf() specifier

Alright i know this question might some weird , but still i wanted to demystify it.
1.)an int type in C can stores number in the range of -2147483648 to 2147483647.
2.)If we append an unsigned it front of it , the range would become 0 to 2147483647.
3.)The thing is , why do we even bother to use the keyword unsigned when the code below could actually works.
The Code:
#include <stdio.h>
int main(void)
{
int num = 2147483650;
printf("%u\n" , num);
return 0;
}
4.)As you see , i can still print out the integer as unsigned type if I use the %u specifier and it will print me the value 2147483650.
5.)Even if I create another integer type with value 50 and sum it up with num , although it's overflow but yet I still can print out the correct sum value by using %u specifier.So why unsigned keyword is still a necessity??
Thanks for spending time reading my question.
No, this is true only on certain platforms (where an int is 32-bit, 2's-complement).
No, in that case the range would be 0 to 4294967295.
That code exhibits undefined behaviour.
See 3.
See 2. and 3.
Considering only Q3, "Why do we bother to use unsigned", consider this program fragment:
int main(void) {
int num = MAX_INT;
num += 50;
printf("%u\n", num); /* Yes, this *might* print what you want */
/* But this "if" almost certainly won't do what you want. */
if(num > 0) {
printf("Big numbers are big\n");
} else {
printf("Big numbers are small\n");
}
}
We use "unsigned" because unsigned int behaves differently from int. There are more interesting behaviors than just how printf works.
Well, firstly the result of assigning an out-of-range number is implementation-defined - it doesn't have to give the value that will "work" when printed with the %u format specifier. But to really answer your question, consider this modification to your code:
#include <stdio.h>
int main(void)
{
int num = 2147483650;
unsigned num2 = 2147483650;
num /= 2;
num2 /= 2;
printf("%u, %u\n" , num, num2);
return 0;
}
(If 2147483650 is out of range of int on your platform, but within the range of unsigned, then you will only get the correct answer of 1073741825 using the unsigned type).
Wrong. The range is INT_MIN (which in 2 completment systems usually is -INT_MAX+1) to INT_MAX; INT_MAX and INT_MIN depends on the compiler, architecture, etc.
Wrong. The range is 0 to UINT_MAX which is usually INT_MAX*2 + 1
Unsigned integers have a different behaviour regarding overflow and semantics. In 2 complement there's one value undefined for signed integers (that is if only the uppermost bit is set, the rest zero), that has somewhat a double meaning. Unsigned integers can make use of the full range of bit patterns.
Here's an exercise: On a 32 bit machine compare the output of printf("%d %u", 0xffffffff, 0xffffffff);
Because unsigned integers behave differently than signed ones.

Resources