Reputation: 85
I want to convert a float number for example 2.45 to the 4 byte char array.
so the 2.45 should look like this '@' 'FS' 'Ì' 'Í'
which is binary the ieee representation of 2.45 = 01000000 00011100 11001100 11001101
?
I've solved the problem but it has a bad complexity. do you have any good ideas?
Thanks for the good answers.
can you please tell me the way back from the char array to the float number ?
Upvotes: 7
Views: 43076
Reputation: 1911
one can convert a float to a char using typecasting and pointers as follows:
float t= -2.63646464;
char *float2CharArr;
float2CharArr = (char*) &t;
Mind you above there's no \0
string terminator. To append it one can do it, for instance, like so:
char* tmp = realloc(float2CharArr, sizeof(*float2CharArr)+1);
tmp[sizeof(*float2CharArr)+1] = '\0';
float2CharArr=tmp;
Another, more elaborate way to convert a float value into a char string can be achieved using the following code below:
union int32_Float_t
{
int32_t Long;
float Float;
};
#ifndef HUGE_VALF
#define HUGE_VALF (__builtin_huge_valf())
#endif
#ifndef FLT_MIN_EXP
#define FLT_MIN_EXP (-999)
#endif
#ifndef FLT_MAX_EXP
#define FLT_MAX_EXP (999)
#endif
#define _FTOA_TOO_LARGE -2 // |input| > 2147483520
#define _FTOA_TOO_SMALL -1 // |input| < 0.0000001
//precision 0-9
#define PRECISION 7
//_ftoa function
void _ftoa(float f, char *p, int *status)
{
int32_t mantissa, int_part, frac_part;
int16_t exp2;
int32_Float_t x;
*status = 0;
if (f == 0.0)
{
*p++ = '0';
*p++ = '.';
*p++ = '0';
*p = 0;
return;
}
x.Float = f;
exp2 = (unsigned char)(x.Long>>23) - 127;
mantissa = (x.Long&0xFFFFFF) | 0x800000;
frac_part = 0;
int_part = 0;
if (exp2 >= 31)
{
*status = _FTOA_TOO_LARGE;
return;
}
else if (exp2 < -23)
{
*status = _FTOA_TOO_SMALL;
return;
}
else if (exp2 >= 23)
{
int_part = mantissa<<(exp2 - 23);
}
else if (exp2 >= 0)
{
int_part = mantissa>>(23 - exp2);
frac_part = (mantissa<<(exp2 + 1))&0xFFFFFF;
}
else
{
//if (exp2 < 0)
frac_part = (mantissa&0xFFFFFF)>>-(exp2 + 1);
}
if (x.Long < 0)
*p++ = '-';
if (int_part == 0)
*p++ = '0';
else
{
ltoa(int_part, p, 10);
while (*p)
p++;
}
*p++ = '.';
if (frac_part == 0)
*p++ = '0';
else
{
char m;
for (m=0; m<PRECISION; m++)
{
//frac_part *= 10;
frac_part = (frac_part<<3) + (frac_part<<1);
*p++ = (frac_part>>24) + '0';
frac_part &= 0xFFFFFF;
}
//delete ending zeroes
for (--p; p[0] == '0' && p[-1] != '.'; --p)
;
++p;
}
*p = 0;
}
Below is an example on how to using on Arduino Studio and related coding platforms for MCU programming:
void setup(void)
{
int i, stat;
char s[20];
float f[] = { 0.0, -0.0, 42.0, 123.456789, 0.0000018, 555555.555,
-888888888.8888888, 11111111.2 };
Serial.begin(9600);
for ( i=0; i<8; i++ )
{
if ( _ftoa(f[i], s, &stat) == 0 )
{
Serial.print( "_ftoa: " );
Serial.println( s );
}
}
}
void loop(void) { }
This source code is posted around the internet in various places, mostly without attribution. For instance here and here. So credit to the anonymous author.
Upvotes: 0
Reputation: 212969
Just use memcpy:
#include <string.h>
float f = 2.45f;
char a[sizeof(float)];
memcpy(a, &f, sizeof(float));
If you require the opposite endianness then it is a trivial matter to reverse the bytes in a
afterwards, e.g.
int i, j;
for (i = 0, j = sizeof(float) - 1; i < j; ++i, --j)
{
char temp = a[i];
a[i] = a[j];
a[j] = temp;
}
Upvotes: 13
Reputation: 409176
You have a few ways of doing this, including these two:
Use typecasting and pointers:
float f = 2.45;
char *s = (char *) &f;
Note that this isn't safe in any way and that there is no string terminator after the "string".
Use a union
:
union u
{
float f;
char s[sizeof float];
};
union u foo;
foo.f = 2.45;
The char array can now be accessed to get the byte values. Also note like the first alternative there is no string terminator.
Upvotes: 10