Integer range and Overflow - c

This is a simple program to convert positive decimal number into binary. I have to report and stop conversion of those numbers which could cause overflow or erroneous results. I found size of integer is 4 Bytes but it converts correctly upto 1023 only.
I am confuse where the number "1023" came from? Is there any method to calculate so i can predict what will be the correct range, if say, i am programming on another system.
#include<stdio.h>
int main(void)
{
int decimal,binary=0,y,m=1;
scanf("%d",&decimal);
if(decimal<=1023)
{
while(decimal>0)
{
y=decimal%2;
binary=binary+(m*y);
m=m*10;
decimal=decimal/2;
}
printf("\nBinary Equivalent is: %d",binary);
}
else
{printf("Sorry, The Number You've entered exceeds the maximum allowable range for conversion");}
getch();
return 0;
}

1023 is equal to 1024-1 (2^10 -1), so a number lesser than or equal to 1023 will have 10 digits in base 2. Since you are using an int to get the result, it stores up to 2^31-1 = 2147483647 (31 because one of the 32 bits is used to represent the sign (+ or -)). When you have a 1024 or higher number, it uses more than 10 digits - and, thus, is higher than 2147483647.
Hope that helps.

Actually, the range of an integer is between [-2^31, 2^31-1]. Because there are 4 bytes (i.e., 32 bits). However, if you want to scanf a non-negative integer. you have to initial a unsigned int rather int. The range will be [0, 2^32-1].

The problem is in the temporary variables binary and m you use. Because 1024 would take 11 divisions to become 0, m will become 10.000.000.000. However, the maximum value of an int is 2.147.483.647 (since one bit of the four bytes is used as a sign bit). m will thus overflow, which results in an incorrect result. 1023 or smaller values will take 10 devisions or less to become 0, so m is max 1.000.000.000, so m has no overflow.

You seem to want to take a 4 byte decimal number and convert it to a binary string of 0s and 1s. The method used in the code fails when the decimal number is > 1023. Here is a conversion that produces a string of 0s and 1s that can be printed using:
printf("\nBinary Equivalent is: ");
while( int i = 0; i < 32; i++ )
{
printf( "%c", (decimal & (1<<i) )? '1': '0');
}
printf("\n");
This eliminates much of the code clutter and produces the desired output.

Related

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'.

How to convert integer to binary form in C [duplicate]

This question already has answers here:
Is there a printf converter to print in binary format?
(57 answers)
Closed 3 years ago.
I'm trying to convert a user entered integer to binary form, but I keep getting a warning that "binary" is not initialized in the last printf statement.
#include <stdio.h>
int main(void)
{
long int integer, binary;
printf("Enter an integer: \n");
scanf("%ld", &integer);
while(integer != 0)
{
binary = integer % 2;
integer = integer / 2;
}
printf("The integer in binary is %ld", binary);
return 0;
}
Welcome to Stack Overflow.
The value binary is set during the while loop, but what happens if you actually enter a zero for the integer? In that case the loop doesn't run, and the value binary has no initialized value. Surprise!
That's why it's complaining.
However, the algorithm you're using, even if you enter a nonzero value, will only give binary the value of the lowest bit in the number you're converting, so you'll need different code to make it work to build up the binary value as you run through the integer.
Basically what you're trying to do is turn a binary value in to a kind of decimal representation of binary, which has enough limitations that I'm not sure it's worth doing.
Still:
long int binary = 0;
while (integer != 0)
{
binary += integer % 2; // 1 or 0
binary *= 10; // a "binary" decimal shift left
integer /= 2;
}
printf("Integer in binary is %ld", binary);
return 0;
}
This works, but it has a severe limitation of only being able to represent relatively small binary values.
The most common way people solve this exercise is to convert the integer value to a string rather than an integer, for easy display.
I wonder if that's the problem you're trying to solve?
An integer comprised of only decimal 1 and 0 digits is not binary. An int on a computer is already binary; the %d format specifier creates a character string representation of that value in decimal. It is mathematically nonsensical to generate a binary value that when represented as a decimal looks like some other binary value. Not least because that approach is good for only a 10 bit value (on a 32 bit int), or 19 bits using a 64bit int.
Moreover, the solution requires further consideration (and more code) to handle negative integer values - although how you do that is ambiguous due to the limited number of bits you can represent.
Since the int is already a binary value, it is far simpler to present the binary bit pattern directly than to calculate some decimal value that happens to resemble a binary value:
// Skip leading zero bits
uint32_t mask = 0x80000000u ;
while( mask != 0 && (integer & mask) == 0 ) mask >>= 1 ;
// Output remaining significant digits
printf("The integer in binary is ");
while( mask != 0 )
{
putchar( (integer & mask) == 0 ? '0' : '1' ) ;
mask >>= 1 ;
}
putchar( '\n' ) ;

Integer overflow (Smallest file size that will make the integer in program become negative in bits)

I have a written a digital sign calculator in C. I need to know is the smallest size of the file (in bytes) which causes the signature to be negative
The program reads in bytes from a file as char then store it in an integer and keeps adding use to the integer until EOF has reached. The program works fine.
FILE *fp;
char inpfile[20];
char c;
int sumdigsig = 0;
// reading in the name of the file using inpfile
printf("Please Enter name of the File:\n");
scanf("%s",inpfile);
// checking if the file exisits
if((fp = fopen(inpfile,"r")) == NULL){
fprintf(stderr,"File does no Exsist\n");
exit(1);
}
// If the file exsists using fgetc to read in until endoffile is reached
// and casting char to int and suming it
c = fgetc(fp);
while(c != EOF){
sumdigsig += (int)c;
c = fgetc(fp);
}
printf("%d\n",sumdigsig);
}
The program works fine, it is just a reference so that you know what is happening. running really large file results in a negative number as expected but I need to know what file size in bits will cause the integer to overflow and be negative.
I need to know what file size in bits will cause the integer to overflow and be negative.
(Do you mean "file size in bytes"? Files are rarely measured in bits.)
The way you are doing it, this all depends upon the bytes in the file. As soon as the sum of the bytes that you are adding together exceeds INT_MAX (see limits.h), the value of the int cumulative sum will wrap to a negative value.
Thus, the maximum number of bytes for a particular file would be one fewer than the number of bytes that caused the summation to exceed INT_MAX. i.e., one less than the number of bytes you have read from the file at the point where the sum first exceeds INT_MAX -- or, in practical terms of detecting this in code, first becomes negative.
And, as one of the comments points out, if all the bytes are 0x00, then even an infinitely large file will never meet this criteria.
EDIT 1 : With respect to the comment about overflow behavior being undefined, instead of detecting if the sum has become negative, test instead whether or not (INT_MAX - sum) is less than the most recently read byte's value, before adding that byte's value to the sum.
EDIT 2 : Expressed in code:
the core loop as I would re-write it
c = 0;
bytes = 0;
while (1) {
if ((c = fgetc(fp)) == EOF) break;
if ((INT_MAX - sumdigsig) >= c) {
sumdigsig += c;
bytes++;
} else {
break;
}
}
sample runs
head -c 1073741824 < /dev/urandom > large-file-of-random-bytes
./sum-file-bytes
Please Enter name of the File : large-file-of-random-bytes
sum is : 2147483572; read 16845621 bytes to reach that sum
head -c 1073741824 < /dev/zero > large-file-of-zeros
./sum-file-bytes
Please Enter name of the File : large-file-of-zeros
sum is : 0; read 1073741824 bytes to reach that sum
In both 64-bit & 32-bit machine, the signed-integer value range is -2,147,483,648 to 2,147,483,647
So if "sumdigsig" crosses the "(positive) maximum value" then it will go back to the negative range.
Let us consider a small example:
Consider if the range is -10 to +9
---> -10 -9 -8 -7 -6 -5 -4 -3 -2 -1 ----
| |
--- +9 +8 +7 +6 +5 +4 +3 +2 +1 0 <---
consider a = 4.
So if you do a = a + 6 i.e then will become -10 because it exceeds the range.
In the same way for an integer, if the value crossed the maximum value, then it will go back to the negative range.
Proof:
#include <stdio.h>
int main()
{
// a contains the maxium value
int a = 2,147,483,647;
a = a + 1;
printf("%d", a);
return 0;
}
Output
-2,147,483,648
Suggestion: Instead of using the signed-integer go with unsigned Integer. U can get a big range i.e 2,147,483,647 + 2,147,483,648

I've created a code to convert binary to decimal, but doesn't work with more than 10 bits

I've created a small code to convert binary number to decimal number.
When I enter a binary number until 10 bits, the result be correct, but when I increase than 10 bits, the result would be wrong.
The algorithm that I used is the following
1 1 0 0 1 0
32 16 8 4 2 1 x
------------------
32+ 16+ 0+ 0+ 2+ 0
The Code:
unsigned long binary, i=0, j=0, result=0, base=1;
unsigned char *binaryStandalone = (unsigned char *)malloc(16);
memset(binaryStandalone, 0, 16);
printf("Enter a binary number: ");
scanf("%u", &binary);
while(binary > 0){
binaryStandalone[i] = binary % 10;
binary = binary / 10;
i++;
}
for(j=0;j<i;j++){
result += (binaryStandalone[j] * 1 << j);
printf("%u = %u\n", j, base << j);
}
printf("The decimal number is: %u\n", result);
free(binaryStandalone);
Now I want to know, what is the reason that the code doesn't give me the correct result when increase the binary number more than 10 bits ?
It seems that your platform uses 32 bit for a long int, therefore your binary
variable can hold at most the value 2^32 - 1 = 4294967295, which is sufficient
for 10 digits, but not for eleven.
You could use unsigned long long instead (64 bit would be sufficient for 20 digits), or read the input as a string.
you store in an unsigned long which has range 0 to 4,294,967,295 -> only 10 numbers
Because the long value you're using to store the "binary" value has not more decimal digits. You might want to use a string type for input instead.

Homework - C bit puzzle - Perform % using C bit operations (no looping, conditionals, function calls, etc)

I'm completely stuck on how to do this homework problem and looking for a hint or two to keep me going. I'm limited to 20 operations (= doesn't count in this 20).
I'm supposed to fill in a function that looks like this:
/* Supposed to do x%(2^n).
For example: for x = 15 and n = 2, the result would be 3.
Additionally, if positive overflow occurs, the result should be the
maximum positive number, and if negative overflow occurs, the result
should be the most negative number.
*/
int remainder_power_of_2(int x, int n){
int twoToN = 1 << n;
/* Magic...? How can I do this without looping? We are assuming it is a
32 bit machine, and we can't use constants bigger than 8 bits
(0xFF is valid for example).
However, I can make a 32 bit number by ORing together a bunch of stuff.
Valid operations are: << >> + ~ ! | & ^
*/
return theAnswer;
}
I was thinking maybe I could shift the twoToN over left... until I somehow check (without if/else) that it is bigger than x, and then shift back to the right once... then xor it with x... and repeat? But I only have 20 operations!
Hint: In decadic system to do a modulo by power of 10, you just leave the last few digits and null the other. E.g. 12345 % 100 = 00045 = 45. Well, in computer numbers are binary. So you have to null the binary digits (bits). So look at various bit manipulation operators (&, |, ^) to do so.
Since binary is base 2, remainders mod 2^N are exactly represented by the rightmost bits of a value. For example, consider the following 32 bit integer:
00000000001101001101000110010101
This has the two's compliment value of 3461525. The remainder mod 2 is exactly the last bit (1). The remainder mod 4 (2^2) is exactly the last 2 bits (01). The remainder mod 8 (2^3) is exactly the last 3 bits (101). Generally, the remainder mod 2^N is exactly the last N bits.
In short, you need to be able to take your input number, and mask it somehow to get only the last few bits.
A tip: say you're using mod 64. The value of 64 in binary is:
00000000000000000000000001000000
The modulus you're interested in is the last 6 bits. I'll provide you a sequence of operations that can transform that number into a mask (but I'm not going to tell you what they are, you can figure them out yourself :D)
00000000000000000000000001000000 // starting value
11111111111111111111111110111111 // ???
11111111111111111111111111000000 // ???
00000000000000000000000000111111 // the mask you need
Each of those steps equates to exactly one operation that can be performed on an int type. Can you figure them out? Can you see how to simplify my steps? :D
Another hint:
00000000000000000000000001000000 // 64
11111111111111111111111111000000 // -64
Since your divisor is always power of two, it's easy.
uint32_t remainder(uint32_t number, uint32_t power)
{
power = 1 << power;
return (number & (power - 1));
}
Suppose you input number as 5 and divisor as 2
`00000000000000000000000000000101` number
AND
`00000000000000000000000000000001` divisor - 1
=
`00000000000000000000000000000001` remainder (what we expected)
Suppose you input number as 7 and divisor as 4
`00000000000000000000000000000111` number
AND
`00000000000000000000000000000011` divisor - 1
=
`00000000000000000000000000000011` remainder (what we expected)
This only works as long as divisor is a power of two (Except for divisor = 1), so use it carefully.

Resources