Need help understanding code converting doubles to binary in C - c

so below is some code which I am using to understand how to get the binary of a double in C however there are some areas of the code which do not make sense to me and I have tried using print statements to help me but to no avail
#include <stdio.h>
#include <string.h>
#include <limits.h>
void double_to_bits(double val);
int main(void)
{
unsigned idx;
double vals[] = { 10 };
for (idx = 0; idx < 4; idx++ ) {
printf("\nvals[%u]= %+lf-->>", idx, vals[idx] );
double_to_bits(vals[idx] );
}
printf("\n");
return 0;
}
void double_to_bits(double val)
{
unsigned idx;
unsigned char arr[sizeof val];
memcpy (arr, &val, sizeof val);
printf("array is : %s\n", arr);
for (idx=CHAR_BIT * sizeof val; idx-- ; ) {
putc(
( arr[idx/CHAR_BIT] & (1u << (idx%CHAR_BIT) ) )
? '1'
: '0'
, stdout
);
}
}
What does arr[idx/CHAR_BIT] return? I understand say if idx = 63 then we get arr[7] but in print statements these seem to just give random integer values .
Also why does the & operand between arr[idx/CHAR_BIT] and (1u%CHAR_BIT) give 2 weird character symbols? How does the & operand work on these two values?
Thank you for your time and help.

This code defines vals to have one element:
double vals[] = { 10 };
This code uses vals as if it has four elements:
for (idx = 0; idx < 4; idx++ ) {
printf("\nvals[%u]= %+lf-->>", idx, vals[idx] );
double_to_bits(vals[idx] );
}
Because of that, the behavior of the program is not defined by the C standard, and different compilers will do different things. You have not shown us what output you get, so we have no way to analyze what your compiler did. Mine seems to figure that, since vals has only one element, it never needs to bother computing the value of idx in vals[idx]; it can always use vals[0]. So every iteration operates on the value 10. Your compiler may have loaded from memory outside the array and used different values.
What does arr[idx/CHAR_BIT] return?
CHAR_BIT is defined in <limits.h> to be the number of bits in a byte. Because of the definition unsigned char arr[sizeof val];, arr is an array with as many elements (each one byte) as there are bytes in a double. So, for example, if there are 8 bits in a byte and 8 bytes in a double, then arr has 8 8-bit elements, 64 bits total.
Using these example numbers, the for loop iterates idx through the numbers from 63 to 0. Then the code uses idx as a counter of the bits in arr. The expression idx/CHAR_BIT figures out which element of the array contains the bit numbered idx: Each array element has CHAR_BIT bits, bits 0-7 (when CHAR_BIT is 8) are in element 0, bits 8-15 are in element 1, bits 16-23 are in element 2, and so on. So dividing idx by CHAR_BIT and truncating to an integer (which is what the / operator does for integer operands) gives the index of the array element that has the bit with number idx.
Then arr[idx/CHAR_BIT] gets that element. Then we need to pick out the individual bit from that element. idx%CHAR_BIT takes the remainder of idx divided by CHAR_BIT, so it gives the number of a bit within a byte. Then 1u << (idx%CHAR_BIT) shifts 1 by that number. The result is number that, when expressed in binary, has a 1 in the bit with that number and a 0 in other bits.
Then the & operator ANDs that with the array element. If the array element has a 0 where the 1 has been shifted to, the result is zero. If the array element has a 1 where the 1 has been shifted to, the result is that bit (still in its position).
Then ? '1' : '0;' uses the result of that AND to select either the character '1' (if the result is not zero) or the character '0' (if the result is zero). That character is passed to putc for printing.
I understand say if idx = 63 then we get arr[7] but in print statements these seem to just give random integer values .
When the array bounds problem described above is corrected and double_to_bits is passed a valid value, it should print the bits that encoded the value of the double. In most C implementations, this will be 0100000000100100000000000000000000000000000000000000000000000000, which is the encoding in the IEEE-754 binary64 format, also called double precision.
Also why does the & operand between arr[idx/CHAR_BIT] and (1u%CHAR_BIT) give 2 weird character symbols?
You have not shown the weird character symbols or other output, so we have no output to interpret.
The statement printf("array is : %s\n", arr); prints arr as if it were a string containing printable characters, but it is used to contain “raw binary data,” so you should not expect that data to result in meaningful characters when printed. Remove that statement. Also, the fact that your program accessed vals out of bounds could cause other complications in output.

Related

What are bit vectors and how do I use them to convert chars to ints?

Here's the explanation for our task when implementing a set data structure in C "The set is constructed as a Bit vector, which in turn is implemented as an array of the data type char."
My confusion arises from the fact that almost all the functions we're given take in a set and an int as shown in the function below yet our array is made up of chars. How would I call functions if they can only take in ints when I have an array of chars? Here's my attempt att calling the function in my main function as well as the structs and example of function used.
int main(){
set *setA = set_empty();
set_insert("green",setA );
}
struct set {
int capacity;
int size;
char *array;
};
void set_insert(const int value, set *s)
{
if (!set_member_of(value, s)) {
int bit_in_array = value; // To make the code easier to read
// Increase the capacity if necessary
if (bit_in_array >= s->capacity) {
int no_of_bytes = bit_in_array / 8 + 1;
s->array = realloc(s->array, no_of_bytes);
for (int i = s->capacity / 8 ; i < no_of_bytes ; i++) {
s->array[i] = 0;
}
s->capacity = no_of_bytes * 8;
}
// Set the bit
int byte_no = bit_in_array / 8;
int bit = 7 - bit_in_array % 8;
s->array[byte_no] = s->array[byte_no] | 1 << bit;
s->size++;
}
}
TL;DR: The types of the index (value in your case) and the indexed element of an array (array in your case) are independent from each other. There is no conversion.
Most digital systems these days store their value in bits, each of them can hold only 0 or 1.
An integer value can therefore be viewed as a binary number, a value to the base of 2. It is a sequence of bits, each of which assigned a power of two. See the Wikipedia page on two's complement for details. But this aspect is not relevant for your issue.
Relevant is the view that an integer value is a sequence of bits. The simplest integer type of C is the char. It holds commonly 8 bits. We can assign indexes to these bits, and therefore think of them as a "vector", mathematically. Some people start to count "from the left", others start to count "from the right". Other common terms in this area are "MSB" and "LSB", see this Wikipedia page for more.
To access an element of a vector, you use its index. On a common char this is commonly a value between 0 and 7, inclusively. Remember, in CS we start to count from zero. The type of this index can be any integer wide enough to hold the value, for example an int. This is why you use a int in your case. This data type is independent from the type of elements in the vector.
How to solve the problem, if you need more than 8 bits? Well, then you can use more chars. This is the reason why your structure holds (a pointer to) an array of chars. All n chars of the array represent a vector of n * 8 bits, and you call this amount the "capacity".
Another option is to use a wider type, like a long or even a long long. And you can build an array of elements of these types, too. However, the widths of such types are commonly not equal in all systems.
BTW, the mathematical "vector" is the same thing as an "array" in CS. Different science areas, different terms.
Now, what is a "set"? I hope your script explains that a bit better than I can... It is a collection that contains an element only once or not at all. All elements are distinct. In your case the elements are represented by (small) integers.
Given a vector of bits of arbitrary capacity, we can "map" an element of a set on a bit of this vector by its index. This is done by storing a 1 in the mapped bit, if the element is present in the set, or 0, if it is not.
To access the correct bit, we need the index of the single char in the array, and the index of the bit in this char. You calculate these values in the lines:
int byte_no = bit_in_array / 8;
int bit = 7 - bit_in_array % 8;
All variables are of type int, most probably because this is the common type. It can be any other integer type, like a size_t for example, as long as it can hold the necessary values, even different types for the different variables.
With these two values at hand, you can "insert" the element into the set. For this action, you set the respective bit to 1:
s->array[byte_no] = s->array[byte_no] | 1 << bit;
Please note that the shift operator << has a higher precedence than the bit-wise OR operator |. Some coding style rules request to use parentheses to make this clear, but you can also use this even clearer assignment:
s->array[byte_no] |= 1 << bit;

The output value differs from the value received as argument within the function when performing a direct operation

I tried to make 11..10..0 (which is binary number with consecutive 32-n zeros in small digits).
// Can assume that 0 <= n <= 31
int masking(int n) {
return (~0)<<(~n+33);
}
However, when I put 0 in input n, I expected 0, but I got -1(0xffffffff).
Without using input,
(~0)<<(~0+33) gives 0.
(-1)<<32 also gives 0.
I don't know why I got different results.
You might want to consider forcing 64 bit math. According to "C" standard, result of shifting of a variable with N bits is only defined when the number of shifts is less than the size of the variable (0..N-1)
Performing the shift on (~0) (integer, usually 32 bit), will result in undefined behavior for ~n+33 (n=0) since ~n+33 = 32, above the limit of 31.
Changing the code to use (~0L) produce the requested result masking(0) = 0
Assuming that you run on generic Linux - gcc will default to 32 bit integer, 64 bit long and 64 bit pointer.
include <stdio.h>
int masking(int n) {
return (~0UL)<<(~n+33);
}
void main(void)
{
for (int i=0 ; i<4 ; i++) {
printf("M(%d)=%x\n", i, masking(i)) ;
}
}
Output:
M(0)=0
M(1)=80000000
M(2)=c0000000
M(3)=e0000000

using bit-fields as representation for integers in c [duplicate]

This question already has answers here:
bit vector implementation of sets
(2 answers)
Closed 6 years ago.
In my C class we were given an assignment:
Write an interactive program (standard input/output). Define the new type set using typedef which can hold a set of integers in the range 0-127. The data structure has to be as efficient as possible in terms of storage (hint: working with bits). Also you need to define 6 global variables A,B,C,D,E,F of type set. All operations on sets in the program will be on these 6 variables.
This command read_set A,5,6,7,4,5,4,-1 will read user's input of integers while -1 means end of user's input. Other commands a user can use: print_set A - prints the set in increasing order, union_set A,B,C does union on 2 sets and saves the output in a third set, intersect_set A,B,C - determines the intersection of 2 sets and saves the output to a third set.
As far as I understand I need to use bit-fields. I could create a table of integers from 0-127. Then I could create the 6 variables A,B,C,D,E,F using set type definition and giving 128 bit-fields to each variable. Then if a user inputs 15 I would turn on the the bit which represents 15 in the data type. I'm really not sure if this is the way, because it's not clear to me how I would arrange bit-fields such that I can turn on exactly 15-th bit if I need to, I would need to convert somehow an integer to bit-field name... Also print_set prints the set in increasing order so how could I re-arrange bit-fields for this?
Really hope you have some ideas.
Yes, each of the sets called A, B, C, D, E and F is represented by a couple of unsigned long long integers like this:
typedef struct {
unsigned long long high;
unsigned long long low;
} Set;
See https://en.wikipedia.org/wiki/C_data_types
This gives you 128 bits of data in a Set (64 bits for the high numbers 64 to 127, and 64 bits for the low numbers 0 to 63).
Then you just need to do some bit manipulation like this: http://www.tutorialspoint.com/ansi_c/c_bits_manipulation.htm
For a number between 0 and 63, you'd shift 1 to the left x times and then set that bit on the "low" field.
For a number between 64 and 127, you'd shift 1 to the left x-64 times and then set that bit on the "high" field.
Hope this helps!
Using bitfields for this assignment will prove very cumbersome because of alignment issues, and you cannot define arrays of bitfields anyway. I would suggest using an array of bytes (unsigned char) and packing values into this array. A 7-bit value spanning at most 2 bytes.
The array for count values should be allocated with a size of (count + 7) / 8 bytes. In order to conserve space, you can store small sets in an integer and larger sets using an allocated array.
The datatype would look like:
#include <stdint.h>
#include <stdlib.h>
typedef struct set {
size_t count;
union {
uintptr_t v;
unsigned char *a;
};
} set;
Here is how to extract the n-th value:
int get_7bits(const set *s, size_t n) {
if (s == NULL || n >= s->count) {
return -1;
} else
if (n < sizeof(uintptr_t) * CHAR_BIT / 7) {
return (s->v >> (n * 7)) & 127;
} else {
size_t i = n / 7;
int shift = n % 7;
if (shift <= CHAR_BIT - 7) {
/* value fits in one byte */
return (s->a[i] >> shift) & 127;
} else {
/* value spans 2 bytes */
return ((s->a[i] | (s->a[i + 1] << CHAR_BIT)) >> shift) & 127;
}
}
}
You can write the other access functions and complete your assignment.

Return the mantissa as bits

I got a bit trouble with my c code. I am trying to extract the sign, exponent and the mantissa. So far it worked out for sign and exponent. The problem begins with mantissa.
For example, let's take -5.0. 1 bit for sign, 8 bits for the exponent and 23 bits for the mantissa.
This is the binary notation of -5.0:
1 10000001 01000000000000000000000
1 = sign
10000001 = exponent
01000000000000000000000 = mantissa.
I wanna return the bits of the mantissa back.
static int fpmanitssa(uint32_t number) {
uint32_t numbTemp = 8388607;
number = number & numbTemp; //bitwise AND, number should be 2097152.
int numbDiv;
int leftover;
char resultString[23];
size_t idx = 0;
do {
numbDiv = number/2;
leftover = number % 2;
resultString[idx++] = leftover;
number = numbDiv;
} while (number != 0);
return resultString;
What I get as result are negative numbers. I don't know why it isn't working. Could you please help to find the problem?
regards
Hagi
1) Floating-point numbers have significands (with linear scale, also called the fraction portion), not mantissas (with logarithmic scales).
2) Your function is declared to return an int, but you attempt to return resultString, which is an array of char. An array of char is not an int and cannot be automatically converted to an int.
3) If you did return resultString, it would fail because the lifetime of resultString is only the time during function execution; it cannot be used after the function returns. If you do intend to return characters from the function, it should be declared so that the caller passes in an existing array of suitable size or the function dynamically allocates an array (as with malloc) and returns its address to the caller, who is responsible for eventually deallocating it (with free).
4) If you want to return an int with the bits of the encoded significand, and number contains the encoded floating-point number with the encoded significand in the low bits, then all you have to do is remove the high bits with an AND operation and return the low bits.
5) If the array of char is to form a printable numeral rather than numeric bits, then '0' should be added to each one, to convert it from the integer 0 or 1 to the character “0” or “1”. In this case, you may also want a null character at the end of resultString.
6) The bits are assigned to resultString in order from low bit to high bit, which may be the opposite order from desired if resultString is intended to be printed later. (The order may be fine if resultString will only be used for calculation, not printing.)
7) The above presume you want to return only the encoded significand, which is the explicit bits in the floating-point encoding. If you want to return the represented significand, including the implicit bit, then you need a 24th position, and it is 1 if the exponent is non-zero and 0 otherwise. (And presuming, of course, that the number is not a NaN or infinity.)
If you happen to be on uClibc or glibc, you can use ieee754.h and the mantissa field, like so
#include <ieee754.h>
static unsigned int fpmanitssa(float number)
{
ieee754_float x = {.f = number};
return x.mantissa;
}
For one thing, your function declaration specifies that you are returning an int, but then you return resultString, which is a char*. I think you may be relying on automatic type conversion which is not part of C. To get resultString to even look like what you want, you need to add 0x30 to leftover (0x30 is '0' and 0x31 is '1').
Then you would need to null terminate the string and convert it back to an int with atoi().
The following probably doesn't work exactly as you intend, but includes changes to handle the ascii/integer conversions:
static int fpmanitssa(uint32_t number) {
uint32_t numbTemp = 8388607;
number = number & numbTemp; //bitwise AND, number should be 2097152.
int numbDiv;
int leftover;
char resultString[24] = {0};
size_t idx = 0;
do {
numbDiv = number/2;
leftover = number % 2;
resultString[idx++] = leftover + 0x30;
number = numbDiv;
} while (number != 0);
return atoi(resultString);
}

Reading characters on a bit level

I would like to be able to enter a character from the keyboard and display the binary code for said key in the format 00000001 for example.
Furthermore i would also like to read the bits in a way that allows me to output if they are true or false.
e.g.
01010101 = false,true,false,true,false,true,false,true
I would post an idea of how i have tried to do it myself but I have absolutely no idea, i'm still experimenting with C and this is my first taste of programming at such a low level scale.
Thankyou
For bit tweaking, it is often safer to use unsigned types, because shifts of signed negative values have an implementation-dependent effect. The plain char can be either signed or unsigned (traditionally, it is unsigned on MacIntosh platforms, but signed on PC). Hence, first cast you character into the unsigned char type.
Then, your friends are the bitwise boolean operators (&, |, ^ and ~) and the shift operators (<< and >>). For instance, if your character is in variable x, then to get the 5th bit you simply use: ((x >> 5) & 1). The shift operators moves the value towards the right, dropping the five lower bits and moving the bit your are interested in the "lowest position" (aka "rightmost"). The bitwise AND with 1 simply sets all other bits to 0, so the resulting value is either 0 or 1, which is your bit. Note here that I number bits from left significant (rightmost) to most significant (leftmost) and I begin with zero, not one.
If you assume that your characters are 8-bits, you could write your code as:
unsigned char x = (unsigned char)your_character;
int i;
for (i = 7; i >= 0; i --) {
if (i != 7)
printf(",");
printf("%s", ((x >> i) & 1) ? "true" : "false");
}
You may note that since I number bits from right to left, but you want output from left to right, the loop index must be decreasing.
Note that according to the C standard, unsigned char has at least eight bits but may have more (nowadays, only a handful of embedded DSP have characters which are not 8-bit). To be extra safe, add this near the beginning of your code (as a top-level declaration):
#include <limits.h>
#if CHAR_BIT != 8
#error I need 8-bit bytes!
#endif
This will prevent successful compilation if the target system happens to be one of those special embedded DSP. As a note on the note, the term "byte" in the C standard means "the elementary memory unit which correspond to an unsigned char", so that, in C-speak, a byte may have more than eight bits (a byte is not always an octet). This is a traditional source of confusion.
This is probably not the safest way - no sanity/size/type checks - but it should still work.
unsigned char myBools[8];
char myChar;
// get your character - this is not safe and you should
// use a better method to obtain input...
// cin >> myChar; <- C++
scanf("%c", &myChar);
// binary AND against each bit in the char and then
// cast the result. anything > 0 should resolve to 'true'
// and == 0 to 'false', but you could add a '> 1' check to be sure.
for(int i = 0; i < 8; ++i)
{
myBools[i] = ( (myChar & (1 << i) > 0) ? 1 : 0 );
}
This will give you an array of unsigned chars - either 0 or 1 (true or false) - for the character.
This code is C89:
/* we need this to use exit */
#include <stdlib.h>
/* we need this to use CHAR_BIT */
#include <limits.h>
/* we need this to use fgetc and printf */
#include <stdio.h>
int main() {
/* Declare everything we need */
int input, index;
unsigned int mask;
char inputchar;
/* an array to store integers telling us the values of the individual bits.
There are (almost) always 8 bits in a char, but it doesn't hurt to get into
good habits early, and in C, the sizes of the basic types are different
on different platforms. CHAR_BIT tells us the number of bits in a byte.
*/
int bits[CHAR_BIT];
/* the simplest way to read a single character is fgetc, but note that
the user will probably have to press "return", since input is generally
buffered */
input = fgetc(stdin);
printf("%d\n", input);
/* Check for errors. In C, we must always check for errors */
if (input == EOF) {
printf("No character read\n");
exit(1);
}
/* convert the value read from type int to type char. Not strictly needed,
we can examine the bits of an int or a char, but here's how it's done.
*/
inputchar = input;
/* the most common way to examine individual bits in a value is to use a
"mask" - in this case we have just 1 bit set, the most significant bit
of a char. */
mask = 1 << (CHAR_BIT - 1);
/* this is a loop, index takes each value from 0 to CHAR_BIT-1 in turn,
and we will read the bits from most significant to least significant. */
for (index = 0; index < CHAR_BIT; ++index) {
/* the bitwise-and operator & is how we use the mask.
"inputchar & mask" will be 0 if the bit corresponding to the mask
is 0, and non-zero if the bit is 1. ?: is the ternary conditional
operator, and in C when you use an integer value in a boolean context,
non-zero values are true. So we're converting any non-zero value to 1.
*/
bits[index] = (inputchar & mask) ? 1 : 0;
/* output what we've done */
printf("index %d, value %u\n", index, inputchar & mask);
/* we need a new mask for the next bit */
mask = mask >> 1;
}
/* output each bit as 0 or 1 */
for (index = 0; index < CHAR_BIT; ++index) {
printf("%d", bits[index]);
}
printf("\n");
/* output each bit as "true" or "false" */
for (index = 0; index < CHAR_BIT; ++index) {
printf(bits[index] ? "true" : "false");
/* fiddly part - we want a comma between each bit, but not at the end */
if (index != CHAR_BIT - 1) printf(",");
}
printf("\n");
return 0;
}
You don't necessarily need three loops - you could combine them together if you wanted, and if you're only doing one of the two kinds of output, then you wouldn't need the array, you could just use each bit value as you mask it off. But I think this keeps things separate and hopefully easier to understand.

Resources