IEEE 754 arithmitic on 4 bytes(32 bits) - c

I wrote this code to do the IEEE 754 floating point arithmetic on a 4byte string.
It takes in the bytes, converts them to binary and with the binary I get the sign, exponent, and mantissa and then do the calculation.
It all works just about perfectl, 0xDEADBEEF gives me 6259853398707798016 and the true answer is 6.259853398707798016E18, now these are same values and I wont have anything this large in the project I'm working with, all other smaller values put the decimal in the correct place.
Here is my code:
float calcByteValue(uint8_t data[]) {
int i;
int j = 0;
int index;
int sign, exp;
float mant;
char bits[8] = {0};
int *binary = malloc(32*sizeof *binary);
for (index = 0;index < 4;index++) {
for (i = 0;i < 8;i++,j++) {
bits[i] = (data[index] >> 7-i) & 0x01;
if (bits[i] == 1) {
binary[j] = 1;
} else {
binary[j] = 0;
}
}
printf("\nindex(%d)\n", index);
}
sign = getSign(&(binary[0]));
mant = getMant(&(binary[0]));
exp = getExp(&(binary[0]));
printf("\nBinary: ");
for (i = 0;i < 32;i++)
printf("%d", binary[i]);
printf("\nsign:%d, exp:%d, mant:%f\n",sign, exp, mant);
float f = pow(-1.0, sign) * mant * pow(2,exp);
printf("\n%f\n", f);
return f;
}
//-------------------------------------------------------------------
int getSign(int *bin) {
return bin[0];
}
int getExp (int *bin) {
int expInt, i, b, sum;
int exp = 0;
for (i = 0;i < 8;i++) {
b = 1;
b = b<<(7-i);
if (bin[i+1] == 1)
exp += bin[i+1] * b;
}
return exp-127;
}
float getMant(int *bin) {
int i,j;
float b;
float m;
int manBin[24] = {0};
manBin[0] = 1;
for (i = 1,j=9;j < 32;i++,j++) {
manBin[i] = bin[j];
printf("%d",manBin[i]);
}
for (i = 0;i < 24;i++) {
m += manBin[i] * pow(2,-i);;
}
return m;
}
Now, my teacher told me that there is a much easier way where I can just take in the stream of bytes, and turn it into a float and it should work. I tried doing it that way but could not figure it out if my life depended on it.
I'm not asking you to do my homework for me, I have it done and working, but I just need to know if I could of done it differently/easier/more efficiently.
EDIT: there are a couple special cases I need to handle, but it's just things like if the exponent is all zeros blah blah blah. Easy to implement.

The teacher probably had this in mind:
char * str; // your deadbeef
float x;
memcpy(&x, str, sizeof(float));
I would advise against it, for the issues with endianness. But if your teacher wants it, he shall have it.

I think you want a union - just create a union where one member is a 4 character array, and the other a float. Write the first, then read the second.

Looking at what your code does then the "4 byte string" looks like it already contains the binary representation of a 32 bit float, so it already exists in memory at the address specified by data in big endian byte order.
You could probably cast the array data to a float pointer and dereference that (if you can assume the system you are running on is big endian and that data will be correctly aligned for the float type on your platform).
Alternatively if you need more control (for example to change the byte order or ensure alignment) you could look into type punning using a union of a uint8_t array and a float. Copy the bytes into your union's uint8_t array and then read the float member.

Here is my working code:
unsigned char val[4] = {0, 0, 0xc8, 0x41};
cout << val << endl;
cout << "--------------------------------------------" << endl;
float f = *(float*)&val;
cout << f << endl;
return 0;

Related

How to convert large HEX string to INT in C

I got large HEX string in result into int i could be more than 10 ^ 30, and I converted in hex. I need sum (3 hex string) and remove last 12 numbers.
hex example "000000000000000000000000bd4c61f945644cf099d41ab8a0ab2ac5d2533835", "000000000000000000000000000000000000000000000000f32f5908b7f3c000", "00000000000000000000000000000000000000000000000000e969cd49be4000". And I need to sum them and get result into int. Thank you
I "made" a little two functions and they work but i think could be better, and they dont convert to normal integer number
// convert hex to unsigned char decimal
unsigned char div10(unsigned char *hex, unsigned size)
{
unsigned rem = 0;
for(int i = 0; i < size; i++)
{
unsigned n = rem * 256 + hex[i];
hex[i] = n / 10;
rem = n % 10;
}
return rem;
}
unsigned char hex_to_dec_summer(char *local){
unsigned char result[32]={0};
unsigned char output[18]={};
char input[64];
strcpy(input, local);
unsigned char hexnr[sizeof(input)/2]={};
for (int i=0; i<sizeof(input)/2; i++) {
sscanf(&input[i*2], "%02xd", &hexnr[i]);
}
unsigned char hexzero[32] = {0};
unsigned i = 0;
while(memcmp(hexnr, hexzero, sizeof(hexnr)) != 0 && i < sizeof(result))
{
result[sizeof(result) - i - 1] = div10(hexnr, sizeof(hexnr));
i++;
}
printf("\n");
for(unsigned j = 0; j < sizeof output; j++)
{
output[j]=result[j];
printf("%d", output[j]);
}
output[18]='\0';
}
I know how its make in python3 -> int(hex_number, 16)/(10**12) - like that but i need it in c
The reason this sort of thing works so easily in Python is that, unusually, Python supports arbitrary-precision integers natively.
Most languages, including C, use fixed sizes for their native types. To perform arbitrary-precision arithmetic, you generally need a separate library, such as GMP.
Here is a basic example of using GMP to solve your problem:
#include <stdio.h>
#include <gmp.h>
char *inputs[] = {
"000000000000000000000000bd4c61f945644cf099d41ab8a0ab2ac5d2533835",
"000000000000000000000000000000000000000000000000f32f5908b7f3c000",
"00000000000000000000000000000000000000000000000000e969cd49be4000"
};
int main()
{
char outstr[100];
mpz_t x; mpz_init(x);
mpz_t y; mpz_init(y);
mpz_t sum; mpz_init(sum);
mpz_t ten; mpz_init_set_si(ten, 10);
mpz_t fac; mpz_init(fac);
mpz_pow_ui(fac, ten, 12); /* fac = 10**12 */
int i;
for(i = 0; i < 3; i++) {
mpz_set_str(x, inputs[i], 16);
mpz_tdiv_q(y, x, fac);
mpz_add(sum, sum, y); /* sum += x / fac */
}
printf("%s\n", mpz_get_str(outstr, 10, sum));
}
The code is a bit verbose, because arbitrary-precision integers (that is, variables of type mpz_t) have nontrivial memory allocation requirements, and everything you do with them requires explicit function calls. (Working with extended types like this would be considerably more convenient in a language with good support for object-oriented programming, like C++.)
To compile this, you'll need to have GMP installed. On my machine, I used
cc testprog.c -lgmp
When run, this program prints
1080702647035076263416932216315997551
Or, if I changed 10 to 16 in the last line, it would print d022c1183a2720991b1fea332a6d6f.
It will make a slight difference whether you divide by 1012 and then sum, or sum and then divide. To sum and then divide, you could get rid of the line mpz_tdiv_q(y, x, fac) inside the loop, change mpz_add(sum, sum, y) to mpz_add(sum, sum, x), and add the line
mpz_tdiv_q(sum, sum, fac);
outside the loop, just before printing.
It's fairly straight forward to add up the (in this case hex) digits of two strings.
This doesn't try to be "optimal", but it does give a sum (as a string of hex digits). vals[0] acts as the accumulator.
When OP clarifies what is meant by "I need sum (3 hex string) and remove last 12 numbers", this answer could be extended.
If more speed is needed, the accumulator could be allocated and used as an array of uint8_t's (saving converting back to ASCII hex until a final total is available.) Also the LUT to convert ASCII hex to '0-F' could be 'binary' (not requiring the subtraction of ASCII character values.)
Anyway...
#include <stdio.h>
char *vals[] = {
"000000000000000000000000bd4c61f945644cf099d41ab8a0ab2ac5d2533835",
"000000000000000000000000000000000000000000000000f32f5908b7f3c000",
"00000000000000000000000000000000000000000000000000e969cd49be4000",
};
char *frmHex =
"................................................0000000000......"
".777777..........................WWWWWW.........................";
char *tohex = "0123456789ABCDEF";
void addTo( char *p0, char *p1 ) {
printf( " %s\n+ %s\n", p0, p1 );
char *px = p0 + strlen( p0 ) - 1;
char *py = p1 + strlen( p1 ) - 1;
for( int carry = 0; px >= p0 && py >= p1; px--, py-- ) {
int val = *px - frmHex[ *px ] + *py - frmHex[ *py ] + carry;
carry = val / 0x10; *px = tohex[ val % 0x10 ];
}
printf( "= %s\n\n", p0 );
}
int main() {
addTo( vals[ 0 ], vals[ 1 ] );
addTo( vals[ 0 ], vals[ 2 ] );
return 0;
}
Output
000000000000000000000000bd4c61f945644cf099d41ab8a0ab2ac5d2533835
+ 000000000000000000000000000000000000000000000000f32f5908b7f3c000
= 000000000000000000000000BD4C61F945644CF099D41AB993DA83CE8A46F835
000000000000000000000000BD4C61F945644CF099D41AB993DA83CE8A46F835
+ 00000000000000000000000000000000000000000000000000e969cd49be4000
= 000000000000000000000000BD4C61F945644CF099D41AB994C3ED9BD4053835
If this were to progress (and use binary accumulators), 'compaction' after summing would quickly lead into integer division (that could be done simply with shifting and repeated subtraction.) Anyway...

Two's complement and loss of information in C

I want do the two's complement of a float data.
unsigned long Temperature ;
Temperature = (~(unsigned long)(564.48))+1;
But the problem is that the cast loses information, 564 instead of 564.48.
Can i do the two's complement without a loss of information?
That is a very weird thing to do; floating-point numbers are not stored as 2s complement, so it doesn't make a lot of sense.
Anyway, you can perhaps use the good old union trick:
union {
float real;
unsigned long integer;
} tmp = { 564.48 };
tmp.integer = ~tmp.integer + 1;
printf("I got %f\n", tmp.real);
When I tried it (on ideone) it printed:
I got -0.007412
Note that this relies on unspecified behavior, so it's possible it might break if your compiler does not implement the access in the most straight-forward manner. This is distinct form undefined behavior (which would make the code invalid), but still not optimal. Someone did tell me that newer standards make it clearer, but I've not found an exact reference so ... consider yourself warned.
You can't use ~ over floats (it must be an integer type):
#include <stdio.h>
void print_binary(size_t const size, void const * const ptr)
{
unsigned char *b = (unsigned char *) ptr;
unsigned char byte;
int i, j;
for (i = size - 1; i >= 0; i--) {
for (j = 7; j >= 0; j--) {
byte = b[i] & (1 << j);
byte >>= j;
printf("%u", byte);
}
}
printf("\n");
}
int main(void)
{
float f = 564.48f;
char *p = (char *)&f;
size_t i;
print_binary(sizeof(f), &f);
for (i = 0; i < sizeof(float); i++) {
p[i] = ~p[i];
}
print_binary(sizeof(f), &f);
f += 1.f;
return 0;
}
Output:
01000100000011010001111010111000
10111011111100101110000101000111
Of course print_binary is there for test the result, remove it, and (as pointed out by #barakmanos) print_binary assumes little endian, the rest of the code is not affected by endiannes:
#include <stdio.h>
int main(void)
{
float f = 564.48f;
char *p = (char *)&f;
size_t i;
for (i = 0; i < sizeof(float); i++) {
p[i] = ~p[i];
}
f += 1.f;
return 0;
}
Casting a floating-point value to an integer value changes the "bit contents" of that value.
In order to perform two's complement on the "bit contents" of a floating-point value:
float f = 564.48f;
unsigned long Temperature = ~*(unsigned long*)&f+1;
Make sure that sizeof(long) == sizeof(float), or use double instead of float.

Printing binary representation of a char in C [duplicate]

This question already has answers here:
Conversion of Char to Binary in C
(3 answers)
Closed 9 years ago.
I want a really basic way to print out the binary representation of a char. I can't seem to find any example code anywhere.
I assumed you could do it in a few lines but everything I find is overly long and complex using lots of functions I haven't used before. atoi comes up a lot but it's not standard.
Is there a simple function or simple way of writing a function to take a char variable and then print out a binary representation?
Eg: char 'x' is the argument taken in by the function and "x is 0111 1000" is printed out.
It's for a school assignment where I must take user input of a string and print out the string in binary. I just need to get the basics of converting a char to binary but i'm struggling at the moment.
What you'd want to do is use bitwise operators to mask the bits one by one and print them to the standard output.
A char in C is guaranteed to be 1 byte, so loop to 8.
Within each iteration, mask off the highest order bit.
Once you have it, just print it to standard output.
Here is a quick stab which hopefully makes sense...
main() {
char a = 10;
int i;
for (i = 0; i < 8; i++) {
printf("%d", !!((a << i) & 0x80));
}
printf("\n");
return 0;
}
CodePad.
In order to get the bit, I shift to the left to get the numbered bit (highest to lowest so printing it is easy) and then mask it off. I then translate it to 0 or 1 with !!.
you can use this method
const char *byte_to_binary(int x)
{
static char b[9];
b[0] = '\0';
int z;
for (z = 128; z > 0; z >>= 1)
{
strcat(b, ((x & z) == z) ? "1" : "0");
}
return b;
}
to get the binary representation and print with it
for example
printf("%s\n", byte_to_binary(15));
void printBits(size_t const size, void const * const ptr)
{
unsigned char *b = (unsigned char*) ptr;
unsigned char byte;
int i, j;
for (i=size-1;i>=0;i--)
{
for (j=7;j>=0;j--)
{
byte = b[i] & (1<<j);
byte >>= j;
printf("%u", byte);
}
}
puts("");
}
int main(int argv, char* argc[])
{
int i = 23;
uint ui = UINT_MAX;
float f = 23.45f;
printBits(sizeof(i), &i);
printBits(sizeof(ui), &ui);
printBits(sizeof(f), &f);
return 0;
}
Try this:-
#include <limits.h>
char *chartobin ( unsigned char c )
{
static char bin[CHAR_BIT + 1] = {0};
int i;
for( i = CHAR_BIT - 1; i >= 0; i-- )
{
bin[i] = (c % 2) + '0';
c /= 2;
}
return bin;
}

UTF-8 decoder fails on non-ASCII characters

Note: if you've followed my recent questions, you'll see that they're all about my Unicode library exercise in C -- as one of my first few serious projects in C, I'm having many problems, so I'm sorry if I'm asking too many questions about one thing.
Part of my library decodes UTF-8 encoded char pointers into raw unsigned code points. However, certain planes don't decode correctly. Let's take a look at the (relevant) code:
typedef struct string {
unsigned long length;
unsigned *data;
} string;
// really simple stuff
string *upush(string *s, unsigned c) {
if (!s->length) s->data = (unsigned *) malloc((s->length = 1) * sizeof(unsigned));
else s->data = (unsigned *) realloc(s->data, ++s->length * sizeof(unsigned));
s->data[s->length - 1] = c;
return s;
}
// UTF-8 conversions
string ctou(char *old) {
unsigned long i, byte = 0, cur = 0;
string new;
new.length = 0;
for (i = 0; old[i]; i++)
if (old[i] < 0x80) upush(&new, old[i]);
else if (old[i] < 0xc0)
if (!byte) {
byte = cur = 0;
continue;
} else {
cur |= (unsigned)(old[i] & 0x3f) << (6 * (--byte));
if (!byte) upush(&new, cur), cur = 0;
}
else if (old[i] < 0xc2) continue;
else if (old[i] < 0xe0) {
cur = (unsigned)(old[i] & 0x1f) << 6;
byte = 1;
}
else if (old[i] < 0xf0) {
cur = (unsigned)(old[i] & 0xf) << 12;
byte = 2;
}
else if (old[i] < 0xf5) {
cur = (unsigned)(old[i] & 0x7) << 18;
byte = 3;
}
else continue;
return new;
}
All upush does, by the way, is pushes a code point onto the end of a string, reallocating memory as needed. ctou does the decoding work, and stores the number of bytes still needed in a sequence in byte, as well as the in-progress code point in cur.
The code all seems correct to me. Let's try decoding U+10ffff, which is f4 8f bf bd in UTF-8. Doing this:
long i;
string b = ctou("\xf4\x8f\xbf\xbd");
for (i = 0; i < b.length; i++)
printf("%z ", b.data[i]);
should print out:
10ffff
but instead it prints out:
fffffff4 ffffff8f ffffffbf ffffffbd
which is basically the four bytes of UTF-8, with ffffff tacked on before it.
Any guidance as to what is wrong in my code?
The char type is allowed to be signed, and conversion to int and then unsigned (which is what happens implicitly when you convert directly to unsigned) shows the error:
#include <stdio.h>
int main() {
char c = '\xF4';
int i = c;
unsigned n = i;
printf("%X\n", n);
n = c;
printf("%X\n", n);
return 0;
}
Prints:
FFFFFFF4
FFFFFFF4
Use unsigned char instead.
You've probably ignored the fact that char is a signed type on your platform. Always use:
unsigned char if you will be reading the actual values of bytes
signed char if you're using bytes as small signed integers
char for abstract strings where you don't care about the values except perhaps for 0.
By the way, your code is extremely inefficient. Instead of calling realloc over and over per-character, why not allocate sizeof(unsigned)*(strlen(old)+1) to begin with, then reduce the size at the end if it's too big? Of course this is only one of the many inefficiencies.

How would you count the number of bits set in a floating point number?

How do you count the number of bits set in a floating point number using C functions?
#include <stdio.h> /* for printf() */
#include <limits.h> /* for CHAR_BIT */
int main(void) {
/* union method */
{
/* a union can only be initialized for the first option in the union */
union { float f; char cs[sizeof(float)]; } const focs = { 1.0 };
int j,k;
int count = 0;
for (j = 0; j < sizeof(float); j++)
{
char const byte = focs.cs[j];
for (k = 0; k < CHAR_BIT; k++)
{
if ((1 << k) & byte)
{
count++;
}
}
}
printf("count(%2.1f) = %d\n", focs.f, count);
}
/* cast method */
{
float const f = 2.5;
int j,k;
int count = 0;
for (j = 0; j < sizeof(float); j++)
{
char const byte = ((char *)&f)[j];
for (k = 0; k < CHAR_BIT; k++)
{
if ((1 << k) & byte)
{
count++;
}
}
}
printf("count(%2.1f) = %d\n", f, count);
}
return 0;
}
If you want to work on the actual bitwise representation of a floating point number, you should do something like this:
float f; /* whatever your float is */
int i = *(int *)&f;
What this does is take the address of f with the address-of operator, &. This address is of type float *, a pointer to a float. Then it recasts it with (int *), which says "pretend this pointer doesn't point to a float anymore, but now it points to an int". Note that it doesn't change the value at f at all. Then the last * (or first, since we read right-to-left) dereferences this pointer, which is a pointer to an int, and therefore returns an int, a.k.a. the integer with the same bitwise representation as the float.
To do the opposite (convert and int i back to a float f), do the opposite:
f = *(float *)&i;
Unless I am mistaken, this operation is undefined by the C standard, but will probably work on most computers and compilers. It is undefined because I believe the actual floating-point representation of numbers is implementation-dependent, and can be left to the CPU or the compiler, and therefore the value of i is almost impossible to predict after this operation (same goes for the value of f in the reverse operation). It is famously used in John Carmack's inverse square root function for the same nefarious purpose.
Anyway, if you're doing this in real code, you should probably stop and think twice about what you're trying to do and why you're using floats to do it. However, if you're just doing this out of curiosity, or you have thought about these and are sure of your design and methods, go for it.
I'm led to believe that you already know how to count the number of bits set in a regular integer, as this is a much easier task. If you don't know, your compiler (or the C language, I don't even know) may have a function to count bits, or you could use something from the wonderful Bit-Twiddling Hacks website, which has ways to do things like this with bitwise operations (which should be pretty fast).
A nice function for counting set bits in an integer mentioned by the first answer:
int NumberOfSetBits(int i)
{
i = i - ((i >> 1) & 0x55555555);
i = (i & 0x33333333) + ((i >> 2) & 0x33333333);
return ((i + (i >> 4) & 0xF0F0F0F) * 0x1010101) >> 24;
}
To use it on your float you would do something like this:
//...
float f;
//...
int numBitsOfF = NumberOfSetBits(*(int*) &f);
You mean the bits set in the IEEE-754 single precision representation of a number? If so, cast it to int (both float and int are 32bit wide) and do a regular bit count: SO question #109023.
The following function will find the number of bits in a 32-bit number. Just type case your float with integer and call this function by a cast
float f=3.14f;
count_bits(*(int *)&f);
int count_bits(int v)
{
// count the number of bits set in v
int c; // c accumulates the total bits set in v
int b=v;
for (c = 0; v; c++)
{
v &= v - 1; // clear the least significant bit set
}
//printf("No of bits in %d is %d\n",b,c);
return c;
}

Resources