I have been trying for the past several hours to convert a negative binary with the first bit as 1 to a decimal. The twos complement conversion seems to be impossible but I believe there has to be some easier way to do this because this is just the beginning of a beginner class in C.
int power;
int count = 0;
int length = strlen(value);
int result = 0;
int negResult = 0;
int i = length - 1;
int j;
if (value[0] == '1') {
for (; i >= 0; i--) {
if (value[i] == '1')
result += 1;
result << 1;
}
printf("%d\n", result);
result = ~result;
result += 1;
printf("%d\n", result);
for (j = 8; j > 0; j--) {
if (result << (8-j) == 1) {
power = (int) pow(2,count);
negResult += power;
}
count++;
}
printf("-%d\n", negResult);
}
else {
for (; i >= 0; i--) {
if (value[i] == '1') {
power = (int) pow(2,count);
result = result + power;
}
count++;
}
printf("%d\n", result);
}
}
I pass it:
binary_to_decimal("10011011");
and I get 5 then -5 and then -0 for each printf.
I did not include the code that actually converts it to a decimal since for positive binaries it works fine and I believe once the twos complement works it should work for negative binaries as well.
You may not be clear about what temp += '0' is doing. It's not making a string, rather it's offsetting an uninitialized pointer and is the cause of the segfault when you come to actually use it as in temp2[j]. To work with strings like I think you're wanting to, check out strcat().
I would junk this and start over. Don't manipulate chars in strings, just convert the string to a binary. Write some code to walk the input string from the first character towards the last. Keep a result integer for your answer, initially 0. As you walk through the string, shift result << 1, and then if you see a char '1', add a number 1 to result. If you see a '0' in the string don't add anything, but in either case do the left shift first.
This will get you a binary of however many bits you have. For negative numbers (topmost (first) bit = '1') you will need to sign extend by OR-ing '1' into all the bits above the sign bit, bitwise-invert the result and add 1. Check this on paper to see how it works, and be aware the input string can't be too long. Good luck with the class.
int length = strlen(value);
unsigned int result = 0;
unsigned int signExtend;
unsigned int negResult = 0;
// assemble incoming chars as bits in an unsigned int
for (int i=0;i<length;i++) {
result = result << 1;
if (value[i] == '1')
result += 1;
}
printf("0x%x, %d\n", result, result); // see it is a hex number and a decimal
// if negative, convert to positive number
if (value[0] == '1') {
// first, sign-extend
signExtend = (1 << (length-1));
signExtend -= 1;
signExtend = ~signExtend;
result |= signExtend;
printf("signExtend mask = 0x%x, sign-extended number = %x\n", signExtend, result);
// then, two's complement
negResult = ~result;
negResult += 1;
// show the result with the '-' sign explicitly added:
printf("result is -%d\n", negResult);
// but actually, once you have sign extended,
// you can cast the result as signed and just print it:
printf("result as signed int = %d\n", (int)result);
} else {
// positive result, just print it
printf("result is %d\n", result);
}
here's how I would do it
int btd(char *str)
{
int i , l = strlen(str) , neg = 0;
int res = 0;
for(i = 0 ; i < l ; i++)
{
if(!i)
{
if(str[i] == '1');
neg++;
continue;
}
if(str[i] == '1')
{
res <<= 1;
res |= 1;
}
else
res <<= 1;
}
if(neg)
res *= -1;
return res;
}
Related
Very short, I am having issues understanding the workings of this code, it is much more efficient then my 20 or so lines to get the same outcome. I understand how left shift is supposed to work and the bitwise Or but would appreciate a little guidance to understand how the two come together to make the line in the for loop work.
Code is meant to take in an array of bits(bits) of a given size(count) and return the integer value of the bits.
unsigned binary_array_to_numbers(const unsigned *bits, size_t count) {
unsigned res = 0;
for (size_t i = 0; i < count; i++)
res = res << 1 | bits[i];
return res;
}
EDIT: As requested, My newbie solution that still passed all tests: Added is a sample of possible assignment to bits[]
unsigned binary_array_to_numbers(const unsigned *bits, size_t count)
{
int i, j = 0;
unsigned add = 0;
for (i = count - 1; i >= 0; i--){
if(bits[i] == 1){
if(j >= 1){
j = j * 2;
add = add + j;
}
else{
j++;
add = add + j;
}
}
else {
if( j>= 1){
j = j * 2;
}
else{
j++;
}
}
}
return add;
}
void main(){
const unsigned bits[] = {0,1,1,0};
size_t count = sizeof(bits)/sizeof(bits[0]);
binary_array_to_numbers(bits, count);
}
a breakdown:
every left shift operation on a binary number effectively multiplies
it by 2 0111(7) << 1 = 1110(14)
consider rhubarbdog answer - the operation can be seen as two separate actions. first left-shift (multiply by two) and then OR with the current bit being reviewed
the PC does not distinguish between the value displayed and the binary
representation of the number
lets try and review a case in-which your input is:
bits = {0, 1, 0, 1};
count = 4;
unsigned binary_array_to_numbers(const unsigned *bits, size_t count) {
unsigned res = 0;
for (size_t i = 0; i < count; i++)
res = res << 1 // (a)
res = res | bits[i]; /* (b) according to rhubarbdog answer */
return res;
}
iteration 0:
- bits[i] = 0;
- (a) res = b0; (left shift of 0)
- (b) res = b0; (bitwise OR with 0)
iteration 1:
- bits[i] = 1;
- (a) res = b0; (left shift of 0)
- (b) res = b1; (bitwise OR with 1)
iteration 2:
- bits[i] = 0;
- (a) res = b10; (left shift of 1 - decimal value is 2)
- (b) res = b10; (bitwise OR with 0)
iteration 3:
- bits[i] = 1;
- (a) res = b100; (left shift of 1 - decimal value is 4)
- (b) res = b101; (bitwise OR with 1)
the final result for res is binary(101) and decimal(5) as one would expect
NOTE: the use of unsigned is a must since a signed value will be interpreted as a negative value if the MSB is 1
hope that helps...
consider them as 2 operations i'll re-write res= ... as 2 lines
res = res << 1
res = res | 1
The firs pass res gets set to 1, next time it's shifted *2 then because it's now even +1
I'm building a function that, given an integer, reverses all 32 of its bits (including sign bit), converts that into a new integer, and returns it. I've almost finished it but I've run into two problems:
Part 1:
If I give it test(15); then
buffer = 11110000000000000000000000000000, which is indeed 15 with all the bits reversed.
but if I give it test(-15); then
buffer = 10001111111111111111111111111111, which is NOT right, it should be 10001000000000000000000000000001 (the 1 at the end is the sign bit). So for negative values, building my buffer string is going awry. Should I just change it to a positive integer, reverse the bits, and change the bit at the end to 1? Or is there some easier way of building this string?
Part 2:
"answer", the integer I'm returning that is supposed to represent these numbers, is never accurate. If I give it test(1500) answer = 185, when it should be 1000341504. What's the best way to turn a 32-bit binary number into an integer?
my code:
int test(int var){
printf("reversing %d:\n", var);
char buffer[32];
int i = 0;
int power = sizeof(var) * 8;
int answer = 0;
while(power > 0){
//check the lowest bit and put a 0 or 1 into the array
if((var & 1) == 1){
buffer[i] = '1';
i++;
}
else{
buffer[i] = '0';
i++;
}
//shift to the next bit
var>>= 1;
power--;
}
i++;
buffer[i] = '\0';
printf("\nbuffer = %s", buffer);
//loop through the array in reverse, building the number
while(i > 0){
if(buffer[i] == '0'){
i--;
}
else{
answer += (2 ^ (32 - i)); //here is where I try to add up answer
i--;
}
}
printf("\nanswer = %d \n\n\n\n", answer);
return 0;
}
The incorrect part of your conversion is:
answer += (2 ^ (32 - i))
2 ^ (32 - i)) is 2 XOR (32 - i), because ^ is the XOR-operator.
I'd do the conversion like this:
unsigned int answer = 0, pow=1;
for(int i = sizeof(buffer) - 1; i >= 0; --i)
{
int bit = buffer[i] - '0';
answer += bit * pow;
pow *= 2;
}
By doing it backwards (from 31 to 0), you don't have to use pow or create a
function that does 2 to the power of i. That would give you the integer value
of your binary interpretation, always positive. If you want to the integer value
of a 2-complement binary:
int answer = 0;
unsigned int pow=1;
for(int i = sizeof(buffer) - 1; i > 0; --i)
{
int bit = buffer[i] - '0';
answer += bit * pow;
pow *= 2;
}
if(buffer[0] == '1')
answer |= 0x80000000; // setting last bit
Or the more general solution (doesn't care if answer is signed or unsigned)
int answer = 0; // or unsigned int answer = 0;
size_t len = strlen(buffer);
for(int i = len - 1; i > 0; --i)
{
if(buffer[i] == '1')
answer |= 1 << len - 1 - i;
}
edit
I also found an error on your conversion to string:
char buffer[32];
...
i++;
buffer[i] = '\0';
The buffer hold 32 chars, one for each bit. There is no room left for the
0-terminating byte there, also with i++ you are overflowing the buffer, i
would be 33, so you are overflowing by 2.
If you are not going to treat buffer as a string (no strcpy, no strcmp,
no printf), then you don't have to store the terminating '\0'. Remove the
buffer[i] = '\0'; and that's it.
However you do print it as a string, so you would have to declare buffer as
char buffer[33];
and remove the i++ before buffer[i] = '\0';.
In that case, you would need to change the for loops as well, to
for(i = sizeof(buffer) - 2; i >= 0; --i)
and
for(i = sizeof(buffer) - 2; i > 0; --i)
or strlen(buffer) - 1 instead of sizeof(buffer) - 2 (in case you do the
convertion on another function and you pass the pointer to buffer.
How would I write code in C to assign a decimal number's binary representation to a char variable?
\\ x is the value of the decimal integer
\\ y is length of the binary representation
{
binary[33] = {0};
while(x!=0){
binary[y] = (x%2)+'0';
y--;
x/=2;
}
}
The idea of scanning bits in number is to start with MSB bit of input number and to proceed to the LSB bit. When first 1 is detected, start printing/saving/whatever, even if 0 is later detected.
This is now example, which will print bits of your number, starting to print when it reaches first 1.
#include <stdio.h>
#include "limits.h"
int main() {
unsigned int num = 10;
int y = 0, i;
for (i = sizeof(num) * CHAR_BIT - 1; i >= 0; i--) {
if (num & (1U << i)) {
printf("1");
y++;
} else if (y) {
printf("0");
y++;
}
}
printf("\n");
return 0;
}
Output for num = 10: 1010
If you want to store your result to array, replace printf statements with something similar to: outputBuffer[y] = '1' or '0'
How would I change this function to handle negative numbers? It correctly outputs everything but it does not make the leading bit 1 when negative. I can't do a negative check then simply force the first bit to be 1 because the amount of 0s between the leading bit and rest of the numbers will be off.
char* fromInt(int bin){
static char str[33];
str[1] = '\0';
int n;
for (n = 128; n > 0; n >>= 1){
if( (bin & n) == n){
strcat(str, "1");
}else{
strcat(str, "0");
}
}
return str;
}
I guess what you want is:
char* fromInt(int bin)
{
static char str[33];
str[0] = '0' + ((bin & 0x80000000) == 0x80000000);
str[1] = '\0';
for (int n = 0x40000000; n > 0; n >>= 1) {
if ((bin & n) == n)
strcat(str, "1");
else
strcat(str, "0");
}
return str;
}
The function has two steps. First is to determine the setting of sign bit (assuming that int object has 32 bits and it uses two's complement arithmetic):
(bin & 0x80000000) == 0x80000000
yields either 1 or 0. Because it's about the sign, It might have been written simply as:
'0' + (bin < 0)
The second step is to loop over remaining bits from position 30 to 0, like in the original code.
Here is an example program:
int main(void)
{
printf("%s\n", fromInt(0));
printf("%s\n", fromInt(1536));
printf("%s\n", fromInt(-1));
return 0;
}
This will output:
00000000000000000000000000000000
00000000000000000000011000000000
11111111111111111111111111111111
I have tried to implement crc in c.My logic is not very good.What I have tried is to copy the message(msg) in a temp variable and at the end I have appended number of zeros 1 less than the number of bits in crc's divisor div.
for ex:
msg=11010011101100
div=1011
then temp becomes:
temp=11010011101100000
div= 10110000000000000
finding xor of temp and div and storing it in temp
gives temp=01100011101100000 counting number of zeros appearing before the first '1' of temp and shifting the characters of div right to that number and then repeating the same process until decimal value of temp becomes less than decimal value of div. Which gives the remainder.
My problem is when I append zeros at the end of temp it stores 0's along with some special characters like this:
temp=11010011101100000$#UFI#->Jp#|
and when I debugged I got error
Floating point:Stack Underflow
here is my code:
#include<stdio.h>
#include<conio.h>
#include<math.h>
#include<string.h>
void main() {
char msg[100],div[100],temp[100];
int i,j=0,k=0,l=0,msglen,divlen,newdivlen,ct=0,divdec=0,tempdec=0;
printf("Enter the message\n");
gets(msg);
printf("\nEnter the divisor\n");
gets(div);
msglen=strlen(msg);
divlen=strlen(div);
newdivlen=msglen+divlen-1;
strcpy(temp,msg);
for(i=msglen;i<newdivlen;i++)
temp[i]='0';
printf("\nModified Temp:");
printf("%s",temp);
for(i=divlen;i<newdivlen;i++)
div[i]='0';
printf("\nModified div:");
printf("%s",div);
for(i=newdivlen;i>0;i--)
divdec=divdec+div[i]*pow(2,j++);
for(i=newdivlen;i>0;i--)
tempdec=tempdec+temp[i]*pow(2,k++);
while(tempdec>divdec)
{
for(i=0;i<newdivlen;i++)
{
temp[i]=(temp[i]==div[i])?'0':'1';
while(temp[i]!='1')
ct++;
}
for(i=newdivlen+ct;i>ct;i--)
div[i]=div[i-ct];
for(i=0;i<ct;i++)
div[i]='0';
tempdec=0;
for(i=newdivlen;i>0;i--)
tempdec=tempdec+temp[i]*pow(2,l++);
}
printf("%s",temp);
getch();
}
and this part of the code :
for(i=newdivlen;i>0;i--)
divdec=divdec+div[i]*pow(2,i);
gives error Floating Point:Stack Underflow
The problem is that you wrote a 0 over the NUL terminator, and didn't put another NUL terminator on the string. So printf gets confused and prints garbage. Which is to say that this code
for(i=msglen;i<newdivlen;i++)
temp[i]='0';
printf("\nModified Temp:");
printf("%s",temp);
should be
for(i=msglen;i<newdivlen;i++)
temp[i]='0';
temp[i] = '\0'; // <--- NUL terminate the string
printf("\nModified Temp:");
printf("%s",temp);
You have to do this with integers
int CRC(unsigned int n);
int CRC_fast(unsigned int n);
void printbinary(unsigned int n);
unsigned int msb(register unsigned int n);
int main()
{
char buf[5];
strcpy(buf, "ABCD");
//convert string to number,
//this is like 1234 = 1*1000 + 2*100 + 3*10 + 4, but with hexadecimal
unsigned int n = buf[3] * 0x1000000 + buf[2] * 0x10000 + buf[1] * 0x100 + buf[3];
/*
- "ABCD" becomes just a number
- Any string of text can become a sequence of numbers
- you can work directly with numbers and bits
- shift the bits left and right using '<<' and '>>' operator
- use bitwise operators & | ^
- use basic math with numbers
*/
//finding CRC, from Wikipedia example:
n = 13548; // 11010011101100 in binary (14 bits long), 13548 in decimal
//padding by 3 bits: left shift by 3 bits:
n <<= 3; //11010011101100000 (now it's 17 bits long)
//17 is "sort of" the length of integer, can be obtained from 1 + most significant bit of n
int m = msb(n) + 1;
printf("len(%d) = %d\n", n, m);
int divisor = 11; //1011 in binary (4 bits)
divisor <<= (17 - 4);
//lets see the bits:
printbinary(n);
printbinary(divisor);
unsigned int result = n ^ divisor;// XOR operator
printbinary(result);
//put this in function:
n = CRC(13548);
n = CRC_fast(13548);
return 0;
}
void printbinary(unsigned int n)
{
char buf[33];
memset(buf, 0, 33);
unsigned int mask = 1 << 31;
//result in binary: 1 followed by 31 zero
for (int i = 0; i < 32; i++)
{
buf[i] = (n & mask) ? '1' : '0';
//shift the mask by 1 bit to the right
mask >>= 1;
/*
mask will be shifted like this:
100000... first
010000... second
001000... third
*/
}
printf("%s\n", buf);
}
//find most significant bit
unsigned int msb(register unsigned int n)
{
unsigned i = 0;
while (n >>= 1)
i++;
return i;
}
int CRC(unsigned int n)
{
printf("\nCRC(%d)\n", n);
unsigned int polynomial = 11;
unsigned int plen = msb(polynomial);
unsigned int divisor;
n <<= 3;
for (;;)
{
int shift = msb(n) - plen;
if (shift < 0) break;
divisor = polynomial << shift;
printbinary(n);
printbinary(divisor);
printf("-------------------------------\n");
n ^= divisor;
printbinary(n);
printf("\n");
}
printf("result: %d\n\n", n);
return n;
}
int CRC_fast(unsigned int n)
{
printf("\nCRC_fast(%d)\n", n);
unsigned int polynomial = 11;
unsigned int plen = msb(polynomial);
unsigned int divisor;
n <<= 3;
for (;;)
{
int shift = msb(n) - plen;
if (shift < 0) break;
n ^= (polynomial << shift);
}
printf("result: %d\n\n", n);
return n;
}
Previous problems with string method:
This is infinite loop:
while (temp[i] != '1')
{
ct++;
}
Previous problems with string method:
This one is too confusing:
for (i = newdivlen + ct; i > ct; i--)
div[i] = div[i - ct];
I don't know what ct is. The for loops are all going backward, this makes the code faster sometimes (maybe 1 nanosecond faster), but it makes it very confusing.
There is another while loop,
while (tempdec > divdec)
{
//...
}
This may go on forever if you don't get the expected result. It makes it very hard to debug the code.