Convert ieee 754 float to hex with c - printf - c

Ideally the following code would take a float in IEEE 754 representation and convert it into hexadecimal
void convert() //gets the float input from user and turns it into hexadecimal
{
float f;
printf("Enter float: ");
scanf("%f", &f);
printf("hex is %x", f);
}
I'm not too sure what's going wrong. It's converting the number into a hexadecimal number, but a very wrong one.
123.1443 gives 40000000
43.3 gives 60000000
8 gives 0
so it's doing something, I'm just not too sure what.
Help would be appreciated

When you pass a float as an argument to a variadic function (like printf()), it is promoted to a double, which is twice as large as a float (at least on most platforms).
One way to get around this would be to cast the float to an unsigned int when passing it as an argument to printf():
printf("hex is %x", *(unsigned int*)&f);
This is also more correct, since printf() uses the format specifiers to determine how large each argument is.
Technically, this solution violates the strict aliasing rule. You can get around this by copying the bytes of the float into an unsigned int and then passing that to printf():
unsigned int ui;
memcpy(&ui, &f, sizeof (ui));
printf("hex is %x", ui);
Both of these solutions are based on the assumption that sizeof(int) == sizeof(float), which is the case on many 32-bit systems, but isn't necessarily the case.

When supported, use %a to convert floating point to a standard hexadecimal format. Here is the only document I could find that listed the %a option.
Otherwise you must pull the bits of the floating point value into an integer type of known size. If you know, for example, that both float and int are 32 bits, you can do a quick cast:
printf( "%08X" , *(unsigned int*)&aFloat );
If you want to be less dependent on size, you can use a union:
union {
float f;
//char c[16]; // make this large enough for any floating point value
char c[sizeof(float)]; // Edit: changed to this
} u;
u.f = aFloat;
for ( i = 0 ; i < sizeof(float) ; ++i ) printf( "%02X" , u.c[i] & 0x00FF );
The order of the loop would depend on the architecture endianness. This example is big endian.
Either way, the floating point format may not be portable to other architectures. The %a option is intended to be.

HEX to Float
I spend quite a long time trying to figure out how to convert a HEX input from a serial connection formatted as IEE754 float into float. Now I got it. Just wanted to share in case it could help somebody else.
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[])
{
uint16_t tab_reg[64] //declare input value recieved from serial connection
union IntFloat { int32_t i; float f; }; //Declare combined datatype for HEX to FLOAT conversion
union IntFloat val;
int i;
char buff[50]; //Declare buffer for string
i=0;
//tab_reg[i]=0x508C; //to test the code without a data stream,
//tab_reg[i+1]=0x4369; //you may uncomment these two lines.
printf("Raw1: %X\n",tab_reg[i]); //Print raw input values for debug
printf("Raw2: %X\n",tab_reg[i+1]); //Print raw input values for debug
rs = sprintf(buff,"0X%X%X", tab_reg[i+1], tab_reg[i]); //I need to swap the words, as the response is with the opposite endianness.
printf("HEX: %s",buff); //Show the word-swapped string
val.i = atof(buff); //Convert string to float :-)
printf("\nFloat: %f\n", val.f); //show the value in float
}
Output:
Raw1: 508C
Raw2: 436A
HEX: 0X436A508C
Float: 234.314636

This approach always worked pretty fine to me:
union converter{
float f_val;
unsigned int u_val;
};
union converter a;
a.f_val = 123.1443f;
printf("my hex value %x \n", a.u_val);

Stupidly simple example:
unsigned char* floatToHex(float val){
unsigned char* hexVals = malloc(sizeof(float));
hexVals[0] = ((unsigned char*)&val)[0];
hexVals[1] = ((unsigned char*)&val)[1];
hexVals[2] = ((unsigned char*)&val)[2];
hexVals[3] = ((unsigned char*)&val)[3];
return hexVals;
}
Pretty obvious solution when I figured it out. No bit masking, memcpy, or other tricks necessary.
In the above example, it was for a specific purpose and I knew floats were 32 bits. A better solution if you're unsure of the system:
unsigned char* floatToHex(float val){
unsigned char* hexVals = malloc(sizeof(float));
for(int i = 0; i < sizeof(float); i++){
hexVals[i] = ((unsigned char*)&val)[i];
}
return hexVals;
}

How about this:?
int main(void){
float f = 28834.38282;
char *x = (char *)&f;
printf("%f = ", f);
for(i=0; i<sizeof(float); i++){
printf("%02X ", *x++ & 0x0000FF);
}
printf("\n");
}

https://github.com/aliemresk/ConvertD2H/blob/master/main.c
Convert Hex to Double
Convert Double to Hex
this codes working IEEE 754 floating format.

What finally worked for me (convoluted as it seems):
#include <stdio.h>
int main((int argc, char** argv)
{
float flt = 1234.56789;
FILE *fout;
fout = fopen("outFileName.txt","w");
fprintf(fout, "%08x\n", *((unsigned long *)&flt);
/* or */
printf("%08x\n", *((unsigned long *)&flt);
}

Related

why itoa fuction returns 32 bits if the size of variable in 16 bit

size of short int is 2 bytes(16 bits) on my 64 bit processor and mingw compiler but when I convert short int variable to a binary string using itoa function
it returns string of 32 bits
#include<stdio.h>
int main(){
char buffer [50];
short int a=-2;
itoa(a,buffer,2); //converting a to binnary
printf("%s %d",buffer,sizeof(a));
}
Output
11111111111111111111111111111110 2
The answer is in understanding C's promotion of short datatypes (and char's, too!) to int's when those values are used as parameters passed to a function and understanding the consequences of sign extension.
This may be more understandable with a very simple example:
#include <stdio.h>
int main() {
printf( "%08X %08X\n", (unsigned)(-2), (unsigned short)(-2));
// Both are cast to 'unsigned' to avoid UB
return 0;
}
/* Prints:
FFFFFFFE 0000FFFE
*/
Both parameters to printf() were, as usual, promoted to 32 bit int's. The left hand value is -2 (decimal) in 32bit notation. By using the cast to specify the other parameter should not be subjected to sign extension, the printed value shows that it was treated as a 32 bit representation of the original 16 bit short.
itoa() is not available in my compiler for testing, but this should give the expected results
itoa( (unsigned short)a, buffer, 2 );
your problem is so simple , refer to itoa() manual , you will notice its prototype which is
char * itoa(int n, char * buffer, int radix);
so it takes an int that to be converted and you are passing a short int so it's converted from 2 byte width to 4 byte width , that's why it's printing a 32 bits.
to solve this problem :
you can simply shift left the array by 16 position by the following simple for loop :
for (int i = 0; i < 17; ++i) {
buffer[i] = buffer[i+16];
}
and it shall give the same result , here is edited version of your code:
#include<stdio.h>
#include <stdlib.h>
int main(){
char buffer [50];
short int a= -2;
itoa(a,buffer,2);
for (int i = 0; i < 17; ++i) {
buffer[i] = buffer[i+16];
}
printf("%s %d",buffer,sizeof(a));
}
and this is the output:
1111111111111110 2

Float to Binary in C

I am asked to convert a float number into a 32 bit unsigned integer. I then have to check if all the bits are zero but I am having trouble with this. Sorry I am new to C
This is what I am doing
float number = 12.5;
// copying number into a 32-bit unsigned int
unsigned int val_number = *((unsigned int*) &number);
At this point I'm very confused on how to check if all bits are zero.
I think I need to loop through all the bits but I don't know how to do that.
To copy the bytes of a 32-bit float to an integer, best to copy to an integer type that is certainly 32-bit. unsigned may be less, same or more than 32-bits.
#include <inttypes.h>
float number = 12.5;
uint32_t val_number32; // 32-bit type
memcpy(&val_number32, &number, sizeof val_number32);
Avoid the cast and assign. It leads to aliasing problems with modern compilers #Andrew.
"... need cast the addresses of a and b to type (unsigned int *) and then dereference the addresses" reflects a risky programing technique.
To test if the bits of the unsigned integer are all zero, simply test with the constant 0.
int bit_all_zero = (val_number32 == 0);
An alternative is to use a union to access the bytes from 2 different encodings.
union {
float val_f;
uint32_t val_u;
} x = { .val_f = 12.5f };
int bit_all_zero = (x.val_u == 0);
Checking if all the bits are zero is equivalent to checking if the number is zero.
So it would be int is_zero = (val_number == 0);

Get float in HEX format

I have the string char str [8]. It says a number in the HEX format. It is float and with a sign. How can I write it to a variable of type float?
For example:
char str[9] = "41700000\0";
I need get val from this: 15.0
You can pun the data:
Using memcpy
unsigned int u = 0x41700000;
float f;
memcpy(&f, &u, sizeof(f));
printf("%f\n", f);
Using union (IMO legal, many people have opposite opinion)
union un
{
float f;
unsigned u;
};
void foo(unsigned x)
{
union un a = {.u = x};
printf("%f\n", a.f);
}
I assume floats && integers have the same size.
Of course you will have to convert string from your question to the unsigned value - but it is relatively easy (scanf, atoi ....)
PS BTW many compilers will generate exactly the same code for both (without the memcpy call) https://godbolt.org/z/VaCcxS
This is a quick and dirty way to revert your 15 back from the hexadecimal 4 bytes representation. There is too much wrong with it to even start talking about it, though, and the right thing to do would be to ask yourself "why do i need this to begin from, and how can i do something better instead".
float hexStrToFloat(const char* str)
{
union { unsigned int i; float f; } tmp;
sscanf_s(str, "%x", &tmp.i);
return(tmp.f);
}
Footnote: assumes little-endian, 32 bit or higher, machine.

Could copy unsigned int bit values as float but float value not returned to the caller function correctly

In the below code, I have bits correct (it was originally bits<float> type in C++ program, but I just used uint32 in this C program.). I want to use the bits as the ieee754 float value. Assigning just float_var = int_val won't do it because it interprets the value and casts to float. I want to just use the bit values as floating point values.
uint32 bits = mantissa_table[offset_table[value>>10]+(value&0x3FF)] + exponent_table[value>>10];
ab_printf("bits = %x\n", bits);
float out;
//memcpy(&out, &bits, sizeof(float)); // original
char *outp = &out;
char *bitsp = &bits;
outp[0] = bitsp[0];
outp[1] = bitsp[1];
outp[2] = bitsp[2];
outp[3] = bitsp[3];
ab_printf("out = %x\n", out);
return out;
part of the program run result :
ff = 3.140000
hh = 4248
bits = 40490000
out = 40092000
There must be something basic I don't know.
For your information, above run is turning float 3.14 to half-precision and back to single precision and I printed the intermediate values. 0x4248 is in half-precision 3.140625 and bits 0x40490000 is in single-precision also 3.140625, so I just need to return it as float.
ADD : After reading comments and answers, I did some experiment and found that the single-float value is seen correct inside the function(using type punning using pointer, or using union), but when it is returned to the calling function, it is not printed correctly. method 0 ~ 3 all don't work. Inline function or not doesn't make any difference. There maybe another fault in our system (an embeded, bare-metal) but hope somebody could tell me what might be wrong here.(I am using part of C++ program in a C program here). (The ldexp, ldexpf didn't work).
== half.h ==
typedef unsigned short uint16;
typedef unsigned short half;
extern uint16 float2half_impl(float value);
extern float half2float_impl(half value);
== test4.c ==
#include "half.h"
int main()
{
float vflt = 3.14;
half vhlf;
float vflt2;
ab_printf("vflt = %f\n", vflt);
vhlf = float2half_impl(vflt);
ab_printf("vhlf = %x\n", *(unsigned short *)&vhlf);
float vflt2 = half2float_impl(vhlf);
ab_printf("received : vflt2 = %f\n", vflt2);
}
== half.c ==
#include "half.h"
....
inline float half2float_impl(uint16 value)
{
//typedef bits<float>::type uint32;
typedef unsigned int uint32;
static const uint32 mantissa_table[2048] = {
....
uint32 bits = mantissa_table[offset_table[value>>10]+(value&0x3FF)] + exponent_table[value>>10];
ab_printf("bits = %x\n", bits);
float out;
#define METHOD 3
#if METHOD == 0
memcpy(&out, &bits, sizeof(float));
return out;
#elif METHOD == 1
#warning METHOD 1
ab_printf("xx = %f\n", *(float *)&bits); // prints 3.140625
return bits;
#elif METHOD == 2 // prints float ok but return value float prints wrong
#warning METHOD 2
union {
unsigned int ui;
float xx;
} aa;
aa.ui = bits;
ab_printf("xx = %f\n", aa.xx); // prints 3.140625
return (float)aa.xx; // but return values prints wrong
#elif METHOD == 3 // prints float ok but return value float prints wrong
#warning METHOD 3
ab_printf("xx = %f\n", *(float *)&bits); // prints 3.140625
return *(float *)&bits; // but return values prints wrong
#else
#warning returning 0
return 0;
#endif
}
How about using a union?
union uint32_float_union
{
uint32_t i;
float f;
};
Then you can do something like
union uint32_float_union int_to_float;
int_to_float.i = bits;
printf("float value = %f\n", int_to_float.f);
Using unions for type punning is explicitly allowed by the C specification.
The memcpy way you have commented out should work to, but really breaks strict aliasing. You could use a byte-buffer as an intermediate though:
char buffer[sizeof(float)];
memcpy(buffer, &bits, sizeof(float));
float value;
memcpy(&value, buffer, sizeof(float));
Of course, all this requires that the value in bits actually corresponds to a valid float value (including correct endianness).
This:
out = *(float *)&bits;
Allows you to read bits as a float without any explicit or implicit conversion by using pointer magic.
Notice, however, that endinaness might get you a bit screwed doing this (just like memcpy() would too, so if it worked for you this method should work too, but keep in mind that this can change from architecture to architecture).
If you can be sure that the value bits of an uint32_t contain exactly the bit pattern of a IEEE754 binary32, you can "construct" your float number without requiring your uint32_t not to contain padding or your float actually conforming to IEEE754 (IOW, quite portably), by using the ldexp() function.
Here's a little example .. note it doesn't support subnormal numbers, NaN and inf; adding them is some work but can be done:
#include <stdint.h>
#include <math.h>
// read IEEE754 binary32 representation in a float
float toFloat(uint32_t bits)
{
int16_t exp = (bits >> 23 & 0xff) - 0x96;
// subtracts exponent bias (0x7f) and number of fraction bits (0x17)
int32_t sig = (bits & UINT32_C(0x7fffff)) | UINT32_C(0x800000);
if (bits & UINT32_C(0x80000000)) sig *= -1;
return ldexp(sig, exp);
}
(you could do something similar to create a float from an uint16_t containing a half precision representation, just adapt the constants for selecting the correct bits)

convert int to float to hex

Using scanf, each number typed in, i would like my program to
print out two lines: for example
byte order: little-endian
> 2
2 0x00000002
2.00 0x40000000
> -2
-2 0xFFFFFFFE
-2.00 0xC0000000
I can get it to print out the 2 in hex
but i also need a float and of course i cant scanf as one
when i need to also scan as an int
If i cast as a float when i try to printf i get a zero. If i scan in as a float
i get the correct output. I have tried to convert the int to a
float but it still comes out as zero.
here is my output so far
Int - float - hex
byte order: little-endian
>2
2 0x000002
2.00 00000000
it looks like i am converting to a float fine
why wont it print as a hex?
if i scan in as a float i get the correct hex representation like the first example.
this should be something simple. i do need to scan in as a decimal
keep in mind
i am running this in cygwin
here is what i have so far..
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[])
{
int HexNumber;
float convert;
printf("Int - float - hex\n");
int a = 0x12345678;
unsigned char *c = (unsigned char*)(&a);
if (*c == 0x78)
{
printf("\nbyte order: little-endian\n");
}
else
{
printf("\nbyte order: big-endian\n");
}
printf("\n>");
scanf("%d", &HexNumber);
printf("\n%10d ",HexNumber);
printf("%#08x",HexNumber);
convert = (float)HexNumber; // converts but prints a zero
printf("\n%10.2f ", convert);
printf("%#08x", convert); // prints zeros
return 0;
}
try this:
int i = 2;
float f = (float)i;
printf("%#08X", *( (int*) &f ));
[EDIT]
#Corey:
let's parse it from inside out:
& f = address of f = say address 0x5ca1ab1e
(int*) &f = interpret the address 0x5ca1ab1e as integer pointer
* ((int*)&f) = get the integer at address 0x5ca1ab1e
the following is more concise, but it's hard to remember the C language's operator associativity and operator precedence(i prefer the extra clarity of some added parenthesis and whitespace provides):
printf("%#08X", *(int*)&f);
printf("%#08x", convert); // prints zeros
This line is not going to work because you are telling printf that you are passing in an int (by using the %x) but infact you are passing it in a float.
What is your intention with this line? To show the binary representation of the floating point number in hex? If so, you may want to try something like this:
printf("%lx\n", *(unsigned long *)(&convert));
What this line is doing is taking the address of convert (&convert) which is a pointer to a float and casting it into a pointer to an unsigned long (note: that the type you cast into here may be different depending on the size of float and long on your system). The last * is dereferencing the pointer to an unsigned long into an unsigned long which is passed to printf
Given an int x, converting to float, then printing out the bytes of that float in hex could be done something like this:
show_as_float(int x) {
float xx = x;
//Edit: note that this really prints the value as a double.
printf("%f\t", xx);
unsigned char *ptr = (unsigned char *)&xx;
for (i=0; i<sizeof(float); i++)
printf("%2.2x", ptr[i]);
}
The standards (C++ and C99) give "special dispensation" for unsigned char, so it's safe to use them to view the bytes of any object. C89/90 didn't guarantee that, but it was reasonably portable nonetheless.

Resources