Using unsigned data types in C - 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;
}

Related

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;
}

Error on casting unsigned int to float

For the following program.
#include <stdio.h>
int main()
{
unsigned int a = 10;
unsigned int b = 20;
unsigned int c = 30;
float d = -((a*b)*(c/3));
printf("d = %f\n", d);
return 0;
}
It is very strange that output is
d = 4294965248.000000
When I change the magic number 3 in the expression to calculate d to 3.0, I got correct result:
d = 2000.000000
If I change the type of a, b, c to int, I also got correct result.
I guess this error occurred by the conversion from unsigned int to float, but I do not know details about how the strange result was created.
I think you realize that you casting minus to unsigned int before assignment to float. If you run the below code, you will get highly likely 4294965296
#include <stdio.h>
int main()
{
unsigned int a = 10;
unsigned int b = 20;
unsigned int c = 30;
printf("%u", -((a*b)*(c/3)));
return 0;
}
The -2000 to the right of your equals sign is set up as a signed
integer (probably 32 bits in size) and will have the hexadecimal value
0xFFFFF830. The compiler generates code to move this signed integer
into your unsigned integer x which is also a 32 bit entity. The
compiler assumes you only have a positive value to the right of the
equals sign so it simply moves all 32 bits into x. x now has the
value 0xFFFFF830 which is 4294965296 if interpreted as a positive
number. But the printf format of %d says the 32 bits are to be
interpreted as a signed integer so you get -2000. If you had used
%u it would have printed as 4294965296.
#include <stdio.h>
#include <limits.h>
int main()
{
float d = 4294965296;
printf("d = %f\n\n", d);
return 0;
}
When you convert 4294965296 to float, the number you are using is long to fit into the fraction part. Now that some precision was lost. Because of the loss, you got 4294965248.000000 as I got.
The IEEE-754 floating-point standard is a standard for representing
and manipulating floating-point quantities that is followed by all
modern computer systems.
bit 31 30 23 22 0
S EEEEEEEE MMMMMMMMMMMMMMMMMMMMMMM
The bit numbers are counting from the least-significant bit. The first
bit is the sign (0 for positive, 1 for negative). The following
8 bits are the exponent in excess-127 binary notation; this
means that the binary pattern 01111111 = 127 represents an exponent
of 0, 1000000 = 128, represents 1, 01111110 = 126 represents
-1, and so forth. The mantissa fits in the remaining 24 bits, with
its leading 1 stripped off as described above. Source
As you can see, when doing conversion 4294965296 to float, precision which is 00011000 loss occurs.
11111111111111111111100 00011000 0 <-- 4294965296
11111111111111111111100 00000000 0 <-- 4294965248
This is because you use - on an unsigned int. The - inverts the bits of the number. Lets print some unsigned integers:
printf("Positive: %u\n", 2000);
printf("Negative: %u\n", -2000);
// Output:
// Positive: 2000
// Negative: 4294965296
Lets print the hex values:
printf("Positive: %x\n", 2000);
printf("Negative: %x\n", -2000);
// Output
// Positive: 7d0
// Negative: fffff830
As you can see, the bits are inverted. So the problem comes from using - on unsigned int, not from casting unsigned intto float.
As others have said, the issue is that you are trying to negate an unsigned number. Most of the solutions already given have you do some form of casting to float such that the arithmetic is done on floating point types. An alternate solution would be to cast the results of your arithmetic to int and then negate, that way the arithmetic operations will be done on integral types, which may or may not be preferable, depending on your actual use-case:
#include <stdio.h>
int main(void)
{
unsigned int a = 10;
unsigned int b = 20;
unsigned int c = 30;
float d = -(int)((a*b)*(c/3));
printf("d = %f\n", d);
return 0;
}
Your whole calculation will be done unsigned so it is the same as
float d = -(2000u);
-2000 in unsigned int (assuming 32bits int) is 4294965295
this gets written in your float d. But as float can not save this exact number it gets saved as 4294965248.
As a rule of thumb you can say that float has a precision of 7 significant base 10 digits.
What is calculated is 2^32 - 2000 and then floating point precision does the rest.
If you instead use 3.0 this changes the types in your calculation as follows
float d = -((a*b)*(c/3.0));
float d = -((unsigned*unsigned)*(unsigned/double));
float d = -((unsigned)*(double));
float d = -(double);
leaving you with the correct negative value.
you need to cast the ints to floats
float d = -((a*b)*(c/3));
to
float d = -(((float)a*(float)b)*((float)c/3.0));
-((a*b)*(c/3)); is all performed in unsigned integer arithmetic, including the unary negation. Unary negation is well-defined for an unsigned type: mathematically the result is modulo 2N where N is the number of bits in unsigned int. When you assign that large number to the float, you encounter some loss of precision; the result, due to its binary magnitude, is the nearest number to the unsigned int that divides 2048.
If you change 3 to 3.0, then c / 3.0 is a double type, and the result of a * b is therefore converted to a double before being multiplied. This double is then assigned to a float, with the precision loss already observed.

C - How to print calculated numbers that have 15 digits?

I tried to print the result of 99,999 * 99,999 * 99,999, the result should have been 999,970,000,299,999 but what got printed instead was 18446744072244127711. I tried to print 20000 * 20000 * 20000 and the result was pretty much the same. Can you guys tell me how to get the real result?
#include <stdio.h>
int main()
{
int num;
printf("Insert number : ");
scanf("%ld", &num);
fflush(stdin);
unsigned long long int total = num * num * num;
printf("Result : %llu", total);
getchar();
return 0;
}
One way to do it is:
#include <inttypes.h>
#include <stdint.h>
#include <stdio.h>
int main(void)
{
uint64_t x = 99999;
printf("%" PRIu64 "\n", x*x*x);
}
You may also be able to do this with unsigned long or unsigned long long types, but these depend on your C implementation (the compiler you are using).
The arithmetic you attempted overflowed the supported range of the int type you were using. When programming, it is important to ensure that the calculations you do will not overflow the range of the types you use.
Additionally, you must be careful about types in C code:
When using scanf, match the conversion specifier to the type. For example, when scanning a decimal numeral for an int object, you should use %d, not %ld. %ld is for long int.
In unsigned long long int total = num*num*num;, the unsigned long long int affects the type of total. It does not affect the type used in the calculation num*num*num. In that expression, the type of num is used. To use unsigned long long int in the calculation, you would have to convert one or all of the operands to unsigned long long int, as by using a cast: (unsigned long long int) num * num * num.
By assigning 99999 to a uint64_t object, which I named x, I ensured that x*x*x was calculated with uint64_t arithmetic. (uint64_t is a 64-bit unsigned integer.) Another way to do this would be with UINT64_C(99999) * UINT64_C(99999) * UINT64_C(99999). UINT64_C is a macro defined in stdint.h that essentially means “treat this constant as having type uint64_t or wider (actually uint_least64_t).” This could also be done with UINT64_C(99999) * 99999 * 99999 because C will automatically convert the narrower-type integer operands to the wider-type integer operand. It could also be done with (uint64_t) 99999 * 99999 * 99999.
PRIu64 is a macro that provides the right printf conversion specifier for uint64_t. It is defined in inttypes.h.
Bugs:
%ld on an int invokes undefined behavior.
fflush(stdin) invokes undefined behavior since stdin is an input stream.
num*num*num is carried out on operands that have type int, so you get overflow if you attempt 99999 * 99999 * 99999 since this is a larger number than 231-1 (assuming 32 bit int).
Fixed code:
#include <stdio.h>
int main(void)
{
int num;
printf("Insert number : ");
scanf("%d",&num); getchar();
long long int total = (long long)num*num*num;
printf("Result : %llu",total);
getchar();
return 0;
}

Weird negative number after % operation

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.

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