I've recently begun working with C again (haven't touched it since my first couple semesters of school) and have been dealing with strings.
Currently, I'm writing a function that will convert an integer into its binary representation in the form of a string.
Here is the code I have to do this:
#include <stdio.h>
float power(int, int); //My version of the pow() function from math.h
char* itob(int);
int main ()
{
int x = 63;
const char * bin_x = itob(x);
printf("x = %d (%s)",x,bin_x);
return 0;
}
char* itob(int a){
static char bin[100];
int i;
for(i=0;((int) power(2,i) < a);i++){
bin[i] = (int)((a & ((int) power(2,i))) >> i);
}
bin[i] = '\0';
return (char*)&bin;
}
The issue I'm having is that the result of the binary operations on a I'm storing into an element of bin[] seems to be '\001' or '\000' as opposed to simply '1' or '0'. Because of this, when I printf() the result in main(), the output looks like a missing character box or if there is a 0 (if x=62 instead of 63) this is interpreted as an end of string character '\0'.
Am I storing these elements into my string incorrectly?
Yes, you are storing it incorrectly. You are storing either a 0 or a 1, but you need to store its encoding instead.
Try to replace this line:
bin[i] = (int)((a & ((int) power(2,i))) >> i);
With:
bin[i] = (int)((a & ((int) power(2,i))) >> i) ? '1' : '0';
And you can simply return bin;, there is no need neither for the cast, nor for the use of the address of operator.
Do not use pow for powers of 2, that's very inefficient, just a shift is enough. Your program wastes lots of time converting between int and float, and another tens of hundreds of cycles for the power while shifting generally takes only 1 cycle (or a little more depending on architecture). And no need to cast to int, any type shorter or equal to int will be automatically promoted to int
bin[i] = a & (1 << i) ? '1' : '0'; // or:
bin[i] = (a >> i) & 1 ? '1' : '0';
Much cleaner, shorter and faster. Another way if branching results in bad performance
bin[i] = ((a >> i) & 1) + '0';
Related
I am trying to convert a decimal value to binary using the function I wrote in C below. I cannot figure out the reason why it is printing 32 zeroes rather than the binary value of 2.
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <limits.h>
int binaryConversion(int num){
int bin_buffer[32];
int mask = INT_MIN;
for(int i = 0; i < 32; i++){
if(num & mask){
bin_buffer[i] = 1;
mask >> 1;
}
else{
bin_buffer[i] = 0;
mask >> 1;
}
}
for(int j = 0; j < 32; j++){
printf("%d", bin_buffer[j]);
}
}
int main(){
binaryConversion(2);
}
Thanks
Two mistakes:
You use >> instead of >>=, so you're not actually ever changing mask.
You didn't declare mask as unsigned, so when you shift, it'll get sign-extended, which you don't want.
If you put a:
printf("%d %d\n", num, mask);
immediately inside your for loop, you'll see why:
2 -2147483648
2 -2147483648
2 -2147483648
2 -2147483648
:
2 -2147483648
The expression mask >> 1 does right shift the value of mask but doesn't actually assign it back to mask. I think you meant to use:
mask >>= 1;
On top of that (once you fix that problem), you'll see that the values in the mask are a bit strange because right-shifting a negative value can preserve the sign, meaning you will end up with multiple bits set.
You'd be better off using unsigned integers since the >> operator will act on them more in line with your expectations.
Additionally, there's little point in writing all those bits into a buffer just so you can print them out later. Unless you need to do some manipulation on the bits (and this appears to not be the case here), you can just output them directly as they're calculated (and get rid of the now unnecessary i variable).
So, taking all those points into account, you can greatly simplify your code such as with the following complete program:
#include <stdio.h>
#include <limits.h>
int binaryConversion(unsigned num) {
for (unsigned mask = (unsigned)INT_MIN; mask != 0; mask >>= 1)
putchar((num & mask) ? '1' : '0');
}
int main(void) {
binaryConversion(2);
putchar('\n');
}
And just one more note, the value of INT_MIN is not actually required to just have the top bit set. Because of the current allowance by C to handle ones' complement and sign-magnitude (as well as two's complement) for negative numbers, it possible for INT_MIN to have a value with multiple bits set (such as -32767).
There are moves afoot to remove these little-used encodings from C (C++20 has already flagged this) but, for maximum portability, you could opt instead for the following function:
int binaryConversion(unsigned int num) {
// Done once to set topBit.
static unsigned topBit = 0;
if (topBit == 0) {
topBit = 1;
while (topBit << 1 != 0) topBit <<= 1;
}
// Loop to process all bits.
for (unsigned mask = topBit; mask != 0; mask >>= 1)
putchar(num & mask ? '1' : '0');
}
This calculates the value with the top bit set the first time you call the function, irrespective of the vagaries of negative encodings. Just watch out if you call it concurrently in a threaded program.
But, as mentioned, this probably isn't necessary, the number of environments that use the other two encodings would be countable on the fingers of a very careless/unlucky industrial machine operator.
You already have your primary question answered regarding the use of >> rather than =>>. However, from a fundamental standpoint there is no need to buffer the 1 and 0 in an array of int (e.g. int bin_buffer[32];) and there is no need to use the variadic printf function to display int values if all you are doing is outputting the binary representation of the number.
Instead, all you need is putchar() to output '1' or '0' depending on whether any bit is set or clear. You can also make your output function a bit more useful by providing the size of the representation you want, e.g. a byte (8-bits), a word (16-bits), and so on.
For example, you could do:
#include <stdio.h>
#include <limits.h>
/** binary representation of 'v' padded to 'sz' bits.
* the padding amount is limited to the number of
* bits in 'v'. valid range: 0 - sizeof v * CHAR_BIT.
*/
void binaryConversion (const unsigned long v, size_t sz)
{
if (!sz) { fprintf (stderr, "error: invalid sz.\n"); return; }
if (!v) { while (sz--) putchar ('0'); return; }
if (sz > sizeof v * CHAR_BIT)
sz = sizeof v * CHAR_BIT;
while (sz--)
putchar ((v >> sz & 1) ? '1' : '0');
}
int main(){
fputs ("byte : ", stdout);
binaryConversion (2, 8);
fputs ("\nword : ", stdout);
binaryConversion (2, 16);
putchar ('\n');
}
Which allows you to set the number of bits you want displayed, e.g.
Example Use/Output
$ ./bin/binaryconversion
byte : 00000010
word : 0000000000000010
There is nothing wrong with your approach, but there may be a simpler way to arrive at the same output.
Let me know if you have further questions.
INT_MIN is a negative number so when you shifted to the right using >>, the most significant bit will still be 1 instead of zero and you will end up in mask=11111...111 all bits have value of 1. Also the mask value is not changing. better use >>= instead. You can try masking on 0x1 and shift the actual value of num instead of the mask like this.
int binaryConversion(int num) {
char bin_buffer[32 + 1]; //+1 for string terminator.
int shifted = num;
for (int i = 31; i >= 0; --i, shifted >>= 1) { //loop 32x
bin_buffer[i] = '0' + (shifted & 0x1);
}
bin_buffer[32] = 0; //terminate the string.
printf("%s", bin_buffer);
}
I'm currently working on a program that (among others) has to convert a decimal number into binary, octal & hexadecimal.
This already works with this code:
int e = 0;
}
while(i != 0){
str[e] = (i%b) + '0';
i = i / b;
if(str[e] > '9'){
str[e] = str[e] + 7;
}
e++;
}
if(vorzeichen == -1){
str[e] = '1';
e++;
}
if(b == 16){
str[e] = 'x';
str[e+1] = '0';
}
else if(b == 8){
str[e] = '0';
}
}
b is the base (2 for binary, 8 for octal & 16 for hexa) and i is the number that i want to convert.
This gives out a string of characters which i then reverse to get the correct number. Now if i try this with negative numbers, it gives out strings not only containing 0 and 1 but also /, which is '0' -1 on the ASCII table. For octal and decimal it also gives out characters below the '/' on the ASCII table. I've attempted different possible solutions but none seemed to give the desired result. What I read on the internet is that I have to use the 2s Complement I'm stuck trying to use it. It just doesn't seem to work for me.
if you want to display a negative decimal you just can convert your int to a unsigned int like this :
unsigned int value = (unsigned int)i;
Now you only have to use value instead of i in your program and it will be fine.
Here's a good explanation of why : Converting negative decimal to binary
When converting between different bases/radixes, always work on unsigned integer types.
Let's say you have long num you wish to convert. Use an unsigned long u. To represent negative values in two's complement format, you can use
if (num < 0)
u = 1 + (~(unsigned long)(-num));
else
u = num;
or even shorter,
unsigned long u = (num < 0) ? 1 + (~(unsigned long)(-num)) : num;
This works on all architectures (except for num == LONG_MIN, in which case the above is technically undefined behaviour), even those that do not use two's complement internally, because we essentially convert the absolute value of num. If num was originally negative, we then do the two's complement to the unsigned value.
In a comment, chux suggested an alternative form which does not rely on UB for num == LONG_MIN (unless LONG_MAX == ULONG_MAX, which would be horribly odd thing to see):
unsigned long u = (num < 0) ? 1 + (~((unsigned long)(-1 - num) + 1)) : num;
This may look "uglier", but a sane C compiler should be able to optimize either one completely away on architectures with two's complement integers. chux's version avoids undefined behaviour by subtracting the negative num from -1, thus mapping -1 to 0, -2 to 1, and so on, ensuring that all negative values are representable as a nonnegative long. That value is then converted to unsigned long. This gets incremented by one, to account for the earlier -1. This procedure yields the correct negation of num.
In other words, to obtain the absolute value of a long, you can use
unsigned long abs_long(const long num)
{
return (num < 0) ? (unsigned long)(-1 - num) + 1u : (unsigned long)num;
}
% is the remainder function, not mod.
With b==2, i%b returns [-1, 0, 1]. This is not the needed functionality for str[e] = (i%b) + '0'; See ... difference between “mod” and “remainder”
This is the cause of '/' and "also gives out characters below the '/' ".
Build up the string from the "right"
With a 2's complement int, a simple approach is to convert to unsigned and avoid a negative result from %. Since code is using % to extract the least significant digit, walk the buffer from right to left.
#include <limits.h>
...
unsigned u = i;
// make a temporary buffer large enough for any string output in binary
// v------v Size of `u` in "bytes"
// | | v------v Size of a "byte" - commonly 8
char my_buff[sizeof u & CHAR_BIT + 1];
int e = 0;
// Form a pointer to the end so code assigns the least significant digits on the right
char *p = &my_buff[sizeof my_buff - 1];
// Strings are null character terminated
*p = '\0';
// Use a `do` loop to insure at least one pass. Useful when `i==0` --> "0"
do {
p--;
p[e] = "0123456789ABCDEF"[u%b]; // Select desired digit
u = u / b;
} while (u);
// "prepend" characters as desired
if(b == 16){
*(--p) = 'x';
*(--p) = '0';
}
else if(b == 8 && i != 0){
*(--p) = '0';
}
strcpy(str, p);
I'm struggling to adapt to C after programming in Java for some time and I need help. What I'm looking for is a method that takes following input:
Integer n, the one to be converted to binary string (character array).
Integer length, which defines the length of the string (positions from the left not filled with the binary numbers are going to be set to default 0).
//Here's some quick code in Java to get a better understanding of what I'm looking for:
public static String convertToBinary(int length, int n) {
return String.format("%1$" + bit + "s", Integer.toBinaryString(value)).replace(' ', '0');
}
System.out.println(convertToBinary(8,1));
// OUTPUT:
00000001 (not just 1 or 01)
Any hints on what the equivalent of this would be in C? Also, could you provide me with an example of how the resulting binary string should be returned?
(not a duplicate, since what I'm looking for is '00000001', not simply '1')
The C standard library does not contain an equivalent function to Integer.toBinaryString(). The good news is, writing such a function won't be too complicated, and if you're in the process of learning C, this problem is fairly ideal for learning how to use the bitwise operators.
You'll want to consult an existing tutorial or manual for all the details, but here are a few examples of the sort of things that would be useful for this or similar tasks. All numbers are unsigned integers in these examples.
n >> m shifts all bits in n right by m steps, and fills in zeros on the left side. So if n = 13 (1101 in binary), n >> 1 would be 6 (i.e. 110), and n >> 2 would be 3 (i.e. 11).
n << m does the same thing, but shifting left. 3 << 2 == 12. This is equivalent to multiplying n by 2 to the power of m. (If it isn't obvious why that is, you'll want to think about how binary numbers are represented for awhile until you understand it clearly; it'll make things easier if you have an intuitive understanding of that property.)
n & m evaluates to a number such that each bit of the result is 1 if and only if it's 1 in both n and m. e.g. 12 & 5 == 4, (1100, 0101, and 0100 being the respective representations of 12, 5, and 4).
So putting those together, n & (1 << i) will be nonzero if and only if bit i is set: 1 obviously only has a single bit set, 1 << i moves it to the appropriate position, and n & (1 << i) checks if that position also has a 1 bit for n. (keeping in mind that the rightmost/least significant bit is bit 0, not bit 1.) So using that, it's a simple matter of checking each bit individually to see if it's 1 or 0, and you have your binary conversion function.
like this:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <limits.h>
char *convertToBinary(int length, int n) {
unsigned num = (unsigned)n;
int n_bit = CHAR_BIT * sizeof(num);
if(length > n_bit){
fprintf(stderr, "specified length greater than maximum length.\n");
length = n_bit;//or expand size?
}
char *bin = malloc(n_bit + 1);//static char bin[CHAR_BIT * sizeof(num)+1]; If you change, memmove(-->return p;), free is not necessary.
memset(bin, '0', n_bit);
bin[n_bit] = 0;
char *p = bin + n_bit;
do {
*--p = "01"[num & 1];
num >>= 1;
}while(num);
int bits = bin + n_bit - p;
if(bits < length){
p -= length - bits;
return memmove(bin, p, length + 1);
} else if(bits > length){
fprintf(stderr, "Specified length is not enough.(%s but length is %d)\n", p, length);
return memmove(bin, p, bits+1);//or cut off
/*
free(bin);
return ""; or return NULL;
*/
}// else if(bits == length)
return bin;
}
int main(void){
char *sbin = convertToBinary(8, 1);
puts(sbin);
free(sbin);
return 0;
}
How to find number of trailing 0s in a binary number?Based on K&R bitcount example of finding 1s in a binary number i modified it a bit to find the trailing 0s.
int bitcount(unsigned x)
{
int b;
for(b=0;x!=0;x>>=1)
{
if(x&01)
break;
else
b++;
}
I would like to review this method.
Here's a way to compute the count in parallel for better efficiency:
unsigned int v; // 32-bit word input to count zero bits on right
unsigned int c = 32; // c will be the number of zero bits on the right
v &= -signed(v);
if (v) c--;
if (v & 0x0000FFFF) c -= 16;
if (v & 0x00FF00FF) c -= 8;
if (v & 0x0F0F0F0F) c -= 4;
if (v & 0x33333333) c -= 2;
if (v & 0x55555555) c -= 1;
On GCC on X86 platform you can use __builtin_ctz(no)
On Microsoft compilers for X86 you can use _BitScanForward
They both emit a bsf instruction
Another approach (I'm surprised it's not mentioned here) would be to build a table of 256 integers, where each element in the array is the lowest 1 bit for that index. Then, for each byte in the integer, you look up in the table.
Something like this (I haven't taken any time to tweak this, this is just to roughly illustrate the idea):
int bitcount(unsigned x)
{
static const unsigned char table[256] = { /* TODO: populate with constants */ };
for (int i=0; i<sizeof(x); ++i, x >>= 8)
{
unsigned char r = table[x & 0xff];
if (r)
return r + i*8; // Found a 1...
}
// All zeroes...
return sizeof(x)*8;
}
The idea with some of the table-driven approaches to a problem like this is that if statements cost you something in terms of branch prediction, so you should aim to reduce them. It also reduces the number of bit shifts. Your approach does an if statement and a shift per bit, and this one does one per byte. (Hopefully the optimizer can unroll the for loop, and not issue a compare/jump for that.) Some of the other answers have even fewer if statements than this, but a table approach is simple and easy to understand. Of course you should be guided by actual measurements to see if any of this matters.
I think your method is working (allthough you might want to use unsigned int). You check the last digit each time, and if it's zero, you discard it an increment the number of trailing zero-bits.
I think for trailing zeroes you don't need a loop.
Consider the following:
What happens with the number (in binary representation, of course) if you subtract 1? Which digits change, which stay the same?
How could you combine the original number and the decremented version such that only bits representing trailing zeroes are left?
If you apply the above steps correctly, you can just find the highest bit set in O(lg n) steps (look here if you're interested in how to do).
Should be:
int bitcount(unsigned char x)
{
int b;
for(b=0; b<7; x>>=1)
{
if(x&1)
break;
else
b++;
}
return b;
}
or even
int bitcount(unsigned char x)
{
int b;
for(b=0; b<7 && !(x&1); x>>=1) b++;
return b;
}
or even (yay!)
int bitcount(unsigned char x)
{
int b;
for(b=0; b<7 && !(x&1); b++) x>>=1;
return b;
}
or ...
Ah, whatever, there are 100500 millions methods of doing this. Use whatever you need or like.
We can easily get it using bit operations, we don't need to go through all the bits. Pseudo code:
int bitcount(unsigned x) {
int xor = x ^ (x-1); // this will have (1 + #trailing 0s) trailing 1s
return log(i & xor); // i & xor will have only one bit 1 and its log should give the exact number of zeroes
}
int countTrailZero(unsigned x) {
if (x == 0) return DEFAULT_VALUE_YOU_NEED;
return log2 (x & -x);
}
Explanation:
x & -x returns the number of right most bit set with 1.
e.g. 6 -> "0000,0110", (6 & -6) -> "0000,0010"
You can deduct this by two complement:
x = "a1b", where b represents all trailing zeros.
then
-x = !(x) + 1 = !(a1b) + 1 = (!a)0(!b) + 1 = (!a)0(1...1) + 1 = (!a)1(0...0) = (!a)1b
so
x & (-x) = (a1b) & (!a)1b = (0...0)1(0...0)
you can get the number of trailing zeros just by doing log2.
I have a C function which accepts a character. I need to extract as well insert bits into that character. I am clear with the extraction part. Can anyone give me an idea of how to insert values to bits?
Pretty vague question, I would suggest you brush up on bitwise operators. This should point you in the right direction.
http://www.cprogramming.com/tutorial/bitwise_operators.html
Since you requested for idea and not exact implementation:
Here is what you can do,
Iterate over each bit and set it as required.
You can set the nth bit (0 indexed as follows)
byteVal = byteVal | (1<<N);
Say you want to check the nth bit of a char:
int checkBit(char c, int n) {
return c & (1 << n);
}
To set the nth bit:
void setBit(char *c, int n) {
*c |= 1 << n;
}
If you want to set the Nth bit in a character to 1, you need to OR it with the value 1 shifted to the left by N positions:
c |= 1 << N;
Sure, simply resort to binary operations. The following function should do exactly what you want, but with a simple interface:
char set8 (char ch, int index) {
if (index >= 1 && index <= 8) {
return (char)(ch | (1 << index - 1));
}
return ch;
}
int n = 0;
set8(n, 1); // Returns 1
set8(n, 2); // Returns 2
set8(n, 3); // Returns 4
...
set8(n, 9); // Returns n (0)
The function uses bitwise-OR to toggle the specified bit. If the index specified is outside the range of a byte (8 bits), then it simply returns the character passed in.