reverse number for max unsigned int - c

I try to write a program for reverse the user input number.
The user input range is from 0 < a < 4294967295,
here is EDITED code.
unsigned long int reverseNumber(unsigned long int num)
{
unsigned long int rev = 0;
while (num > 0)
{
rev = rev *10 + (num%10);
num = num/10;
}
return rev;
}
The problem is when I input 4294967295, it will output 1632727628.
Why? I have no idea why it happened.
How can I reverse the 4294967295.
I had changed it to unsigned long int, printf by using %lu, but still output 1632727628. Why?

The reverse of 4294967295 is 5927694924 which is greater than the range of unsigned int
In your system, unsigned int is 32-bit wide, hence the max value that an unsigned int can represent is 4294967295 i.e. 0xFFFFFFFF. That is why your result is overflowing and whatever remains in 32 bits is shown as output.
If you represent 5927694924 in hex, it is 0x16151724C which has extra 33rd bit 1, which is discarded and hence output is 0x6151724C which is 1632727628 in decimal.
To print it on screen you need a greater data type like unsigned long long or uint64_t or unsigned long (on 64-bit systems only), whatever your compiler supports for 64 bit integers.

The reverse of 4294967295 is 5927694924, which is greater than 4294967295, which is the greatest integer which can be stored on 32 bit.

The problem is when I input 4294967295, it will output 1632727628. Why?
unsigned int can store 2^32-1 max. The reverse of 4294967295 is 5927694924 which is much bigger than 2^32-1. Hence the out put is 1632727628. 1632727628 is in fact 5927694924 % 4294967296
To solve this you should have used unsigned long it. But again if the number is great than highest long it'll overflow again.

Related

The modulo operation doesn't seem to work on a 64-bit value of all ones

So... the modulo operation doesn't seem to work on a 64-bit value of all ones.
Here is my C code to set up the edge case:
#include <stdio.h>
int main(int argc, char *argv[]) {
long long max_ll = 0xFFFFFFFFFFFFFFFF;
long long large_ll = 0x0FFFFFFFFFFFFFFF;
long long mask_ll = 0x00000F0000000000;
printf("\n64-bit numbers:\n");
printf("0x%016llX\n", max_ll % mask_ll);
printf("0x%016llX\n", large_ll % mask_ll);
long max_l = 0xFFFFFFFF;
long large_l = 0x0FFFFFFF;
long mask_l = 0x00000F00;
printf("\n32-bit numbers:\n");
printf("0x%08lX\n", max_l % mask_l);
printf("0x%08lX\n", large_l % mask_l);
return 0;
}
The output shows this:
64-bit numbers:
0xFFFFFFFFFFFFFFFF
0x000000FFFFFFFFFF
32-bit numbers:
0xFFFFFFFF
0x000000FF
What is going on here?
Why doesn't modulo work on a 64-bit value of all ones, but it will on a 32-bit value of all ones?
It this a bug with the Intel CPU? Or with C somehow? Or is it something else?
More Info
I'm on a Windows 10 machine with an Intel i5-4570S CPU. I used the cl compiler from Visual Studio 2015.
I also verified this result using the Windows Calculator app (Version 10.1601.49020.0) by going into the Programmer mode. If you try to modulus 0xFFFF FFFF FFFF FFFF with anything, it just returns itself.
Specifying unsigned vs signed didn't seem to make any difference.
Please enlighten me :) I actually did have a use case for this operation... so it's not purely academic.
Your program causes undefined behaviour by using the wrong format specifier.
%llX may only be used for unsigned long long. If you use the right specifier, %lld then the apparent mystery will go away:
#include <stdio.h>
int main(int argc, char* argv[])
{
long long max_ll = 0xFFFFFFFFFFFFFFFF;
long long mask_ll = 0x00000F0000000000;
printf("%lld %% %lld = %lld\n", max_ll, mask_ll, max_ll % mask_ll);
}
Output:
-1 % 16492674416640 = -1
In ISO C the definition of the % operator is such that (a/b)*b + a%b == a. Also, for negative numbers, / follows "truncation towards zero".
So -1 / 16492674416640 is 0, therefore -1 % 16492674416640 must be -1 to make the above formula work.
As discussed in comments, the following line:
long long max_ll = 0xFFFFFFFFFFFFFFFF;
causes implementation-defined behaviour (assuming that your system has long long as a 64-bit type). The constant 0xFFFFFFFFFFFFFFFF has type unsigned long long, and it is out of range for long long whose maximum permitted value is 0x7FFFFFFFFFFFFFFF.
When an out-of-range assignment is made to a signed type, the behaviour is implementation-defined, which means the compiler documentation must say what happens.
Typically, this will be defined as generating the value which is in range of long long and has the same representation as the unsigned long long constant has. In 2's complement , (long long)-1 has the same representation as the unsigned long long value 0xFFFFFFFFFFFFFFFF, which explains why you ended up with max_ll holding the value -1.
Actually it does make a difference whether the values are defined as signed or unsigned:
#include <stdio.h>
#include <limits.h>
int main(void) {
#if ULLONG_MAX == 0xFFFFFFFFFFFFFFFF
long long max_ll = 0xFFFFFFFFFFFFFFFF; // converts to -1LL
long long large_ll = 0x0FFFFFFFFFFFFFFF;
long long mask_ll = 0x00000F0000000000;
printf("\n" "signed 64-bit numbers:\n");
printf("0x%016llX\n", max_ll % mask_ll);
printf("0x%016llX\n", large_ll % mask_ll);
unsigned long long max_ull = 0xFFFFFFFFFFFFFFFF;
unsigned long long large_ull = 0x0FFFFFFFFFFFFFFF;
unsigned long long mask_ull = 0x00000F0000000000;
printf("\n" "unsigned 64-bit numbers:\n");
printf("0x%016llX\n", max_ull % mask_ull);
printf("0x%016llX\n", large_ull % mask_ull);
#endif
#if UINT_MAX == 0xFFFFFFFF
int max_l = 0xFFFFFFFF; // converts to -1;
int large_l = 0x0FFFFFFF;
int mask_l = 0x00000F00;
printf("\n" "signed 32-bit numbers:\n");
printf("0x%08X\n", max_l % mask_l);
printf("0x%08X\n", large_l % mask_l);
unsigned int max_ul = 0xFFFFFFFF;
unsigned int large_ul = 0x0FFFFFFF;
unsigned int mask_ul = 0x00000F00;
printf("\n" "unsigned 32-bit numbers:\n");
printf("0x%08X\n", max_ul % mask_ul);
printf("0x%08X\n", large_ul % mask_ul);
#endif
return 0;
}
Produces this output:
signed 64-bit numbers:
0xFFFFFFFFFFFFFFFF
0x000000FFFFFFFFFF
unsigned 64-bit numbers:
0x000000FFFFFFFFFF
0x000000FFFFFFFFFF
signed 32-bit numbers:
0xFFFFFFFF
0x000000FF
unsigned 32-bit numbers:
0x000000FF
0x000000FF
64 bit hex constant 0xFFFFFFFFFFFFFFFF has value -1 when stored into a long long. This is actually implementation defined because of out of range conversion into a signed type, but on Intel processors, with current compilers, the conversion just keeps the same bit pattern.
Note that you are not using the fixed size integers defined in <stdint.h>: int64_t, uint64_t, int32_t and uint32_t. long long types are specified in the standard as having at least 64 bits, and on Intel x86_64, they do, and long has at least 32 bits, but for the same processor, the size differs between environments: 32 bits in Windows 10 (even in 64 bit mode) and 64 bits on MaxOS/10 and linux64. This is the reason why you observe surprising behavior for the long case where unsigned and signed may produce the same result. They don't on Windows, but they do in linux and MacOS because the computation is done in 64 bits and these values are just positive numbers.
Also note that LLONG_MIN / -1 and LLONG_MIN % -1 both invoke undefined behavior because of signed arithmetic overflow, and this one is not ignored on Intel PCs, it usually fires an uncaught exception and exits the program, just like 1 / 0 and 1 % 0.
Try putting unsigned before your long long. As a signed number, your 0xFF...FF is actually -1 on most platforms.
Also, in your code, your 32-bit numbers are still 64-bits (you have them declared as long long as well).

Unsigned long long with negative value

while exploring linux code, came across many definition like below. If ULL is unsigned long long, why it has negative value -11? What the value of below macro?
#define BTRFS_FREE_SPACE_OBJECTID -11ULL
-11ULL is the same as - (11ULL). 11ULL is an unsigned long long with value 11. If you read up how arithmetic operations on unsigned types work, if the mathematical result does not fit into the range, then the largest value + 1 is added or subtracted repeatedly.
The mathematical result -11 doesn't fit, so the largest unsigned long long + 1 is added, and -11ULL gives ten less than the largest possible unsigned long long value. A huge positive number, not negative.
unsigned int a=-1;
is the same as:
unsigned int a=0xffffffff;

garbage value while usage of unsigned long int

Program:
#include<stdio.h>
int main()
{
unsigned long int i=1902;
int j=0;
while(j<10)
{
i=i*10;
printf("\n%lu",i);
j++;
}
}
Why am I getting correct results only upto 5 iterations? Please help me to get the correct answer for all iterations. Seeing the range, I changed my int to unsigned long int but still I'm unable to correct the error.
My guess is that you're on a 32-bit system, or using the Microsoft Visual Studio compiler. I guess that because it seems that unsigned long is 32 bits, which means the maximum value it can be is a little over 4 billion.
If you want a 64-bit value then you need to use unsigned long long, which is 64 bits on just about all PC-like systems.
Because at that point the value is out of the range that a unsigned long int can represent, that goes from 0 to 4,294,967,295.
unsigned long int is 4 bytes in almost every C Compiler.
here i is initialized with 1902.
You are multiplying the value of i by 10 at each iteration.
The range of signed long int is from -2,147,483,648 to 2,147,483,647.
By making the variable unsigned you can only double the range of positive integers, ie, from 0 to 4,294,967,295.
The value in variable i crosses maximum range of unsigned integer after 6 iterations. Hence the overflow and negative numbers displayed.
If you want to represent larger numbers use long long int whose size is 64 bits and the range is from −9223372036854775807 to 9223372036854775807.

Comparison between big numbers doesn't seem to work

The program I wrote takes two numbers and makes a division and a modulo operation.
The code is
#define ADDRESS_SPACE 4294967295
int main (int argc, char *argv[]) {
long int pagesize = atoi(argv[1]), virtaddr = atoi(argv[2]);
if (virtaddr >= ADDRESS_SPACE) {puts("Address is too large"); return 1;}
printf("%lu\n", virtaddr);
printf("%lu\n", ADDRESS_SPACE);
printf("Page = %lu\nOffset = %lu\n", virtaddr/pagesize, virtaddr%pagesize);
return 0;
}
And doing ./page 1024 9999999999999999999999999999999999999999999999 gives the following output
18446744073709551615
4294967295
Page = 0
Offset = 18446744073709551615
If virtaddr is bigger than ADDRESS_SPACE, why isn't the if statement working? I know there's an overflow, but printing the variables doesn't show any error and they are still numbers (the maximum value a long int can take).
Because atoi converts from ASCII to ints and not to long ints and also 9999999999999999999999999999999999999999999999 is far to big to be converted into an int.
Try using sscanf for the string conversion and also try a more reasonable number.
18446744073709551615 is the unsigned version of -1. virtaddr is signed but you displayed it as unsigned; of course -1 is going to be less than any valid positive number.
atoi returns INT_MAX when the number is out of range. Comparing a 32-bit int to 4294967295 is always false, because INT_MAX is roughly two times smaller. If you use strtoll instead of atoi, your solution will work, because the result will be in the range of long long. Alternatively, you could use INT_MAX instead of ADDRESS_SPACE.

Displaying very large number

As we know that 4294967295 is the largest number in unsigned int if I multiply this number by itself then how to display it? I have tried:
long unsigned int NUMBER = 4294967295 * 4294967295;
but still getting 1 as answer.
You are getting an overflow. Consider the muplication in hexadecimal:
0xffffffff * 0xffffffff == 0xfffffffe00000001
^^^^^^^^
only the last 32 bits are returned
The solution is to use a larger type such as long long unsigned:
long long unsigned int NUMBER = 4294967295ULL * 4294967295ULL;
The suffix ULL means unsigned long long.
See it working online: ideone
The multiplication overflows.
#include <stdio.h>
int main()
{
unsigned int a = 4294967295;
unsigned int b = 4294967295;
// force to perform multiplication based on larger type than unsigned int
unsigned long long NUMBER = (unsigned long long)a * b;
printf("%llu\n", NUMBER);
}
You state in your question that you know max int is equal to 4294967295. That means that you can't store a number larger than that if you are using unsigned int.
C longs store up to 18,446,744,073,709,551,615 when unsigned on a 64 bit unix system [source] so you need only suffix your numbers with UL : 4294967295UL
If you aren't using a 64-bit unix system then you should use long long unsigned int and suffix with LL
Yes, it's an overflow. If you are using c, there isn't any easy way to do such big number multiply as i knew. Maybe you need write one by yourself. In fact some language support such features originally.

Resources