Converting 4 bytes to a float

L

Larry.Martell

I have a situation where I have to read in 4 values from a text file,
then convert that into a float that I can use for arithmetic.

For example, the file contains "85,170,174,214" - I read this in, and
split it into an array, @d

In C, I would do something akin to this:

union convert_float32 {
float f; // float view
unsigned int i; // uint32 view
} c;
unsigned char i[4];
char *q;

for (int j=0; j<4; j++) i[j] = (unsigned char)strtoul(d[j], &q, 10);
c.i = ((unsigned int)i[0] << 24) | ((unsigned int)i[1] << 16) |
((unsigned int)i[2] << 8) | (unsigned int)i[3];

and c.f would have the value I want (in this example
23458486419456.000000)

Is there some way I can achieve the result with perl?

TIA!
-larry




How can I do a similar conversion in perl?
 
B

Brian McCauley

I have a situation where I have to read in 4 values from a text file,
then convert that into a float that I can use for arithmetic.

For example, the file contains "85,170,174,214" - I read this in, and
split it into an array, @d

In C, I would do something akin to this:

union convert_float32 {
float f; // float view
unsigned int i; // uint32 view} c;

unsigned char i[4];
char *q;

for (int j=0; j<4; j++) i[j] = (unsigned char)strtoul(d[j], &q, 10);
c.i = ((unsigned int)i[0] << 24) | ((unsigned int)i[1] << 16) |
((unsigned int)i[2] << 8) | (unsigned int)i[3];

and c.f would have the value I want (in this example
23458486419456.000000)

Is there some way I can achieve the result with perl?

TIA!
-larry

How can I do a similar conversion in perl?
 
B

Brian McCauley

I have a situation where I have to read in 4 values from a text file,
then convert that into a float that I can use for arithmetic.

For example, the file contains "85,170,174,214" - I read this in, and
split it into an array, @d

In C, I would do something akin to this:

union convert_float32 {
float f; // float view
unsigned int i; // uint32 view
} c;

unsigned char i[4];
char *q;

for (int j=0; j<4; j++) i[j] = (unsigned char)strtoul(d[j], &q, 10);
c.i = ((unsigned int)i[0] << 24) | ((unsigned int)i[1] << 16) |
((unsigned int)i[2] << 8) | (unsigned int)i[3];

and c.f would have the value I want (in this example
23458486419456.000000)

Actually it would make more sense to get rid of the intermediate step.

union convert_float32 {
float f; // float view
unsigned char i[4]; // 4 byte view
} c;
Is there some way I can achieve the result with perl?

You are looking for the pack() and unpack() functions.
 
D

Dr.Ruud

(e-mail address removed) schreef:
I have a situation where I have to read in 4 values from a text file,
then convert that into a float that I can use for arithmetic.

First convert the values into a buffer of 4 bytes. Then use unpack().
See perldoc -f unpack.


$ perl -wle 'print length pack "f", 1.23'
4

$ perl -wle 'print ord for split "", pack "f", 1.23'
164
112
157
63

$ perl -wle 'print unpack "f", chr(164).chr(112).chr(157).chr(63)'
1.23000001907349
 
L

Larry.Martell

I have a situation where I have to read in 4 values from a text file,
then convert that into a float that I can use for arithmetic.
For example, the file contains "85,170,174,214" - I read this in, and
split it into an array, @d
In C, I would do something akin to this:
union convert_float32 {
float f; // float view
unsigned int i; // uint32 view
} c;
unsigned char i[4];
char *q;
for (int j=0; j<4; j++) i[j] = (unsigned char)strtoul(d[j], &q, 10);
c.i = ((unsigned int)i[0] << 24) | ((unsigned int)i[1] << 16) |
((unsigned int)i[2] << 8) | (unsigned int)i[3];
and c.f would have the value I want (in this example
23458486419456.000000)

Actually it would make more sense to get rid of the intermediate step.

union convert_float32 {
float f; // float view
unsigned char i[4]; // 4 byte view

} c;
Is there some way I can achieve the result with perl?

You are looking for the pack() and unpack() functions.

Thanks - I got this to work using unpack().

-larry
 
L

Larry.Martell

(e-mail address removed) schreef:


First convert the values into a buffer of 4 bytes. Then use unpack().
See perldoc -f unpack.

$ perl -wle 'print length pack "f", 1.23'
4

$ perl -wle 'print ord for split "", pack "f", 1.23'
164
112
157
63

$ perl -wle 'print unpack "f", chr(164).chr(112).chr(157).chr(63)'
1.23000001907349

Thanks much - this is exactly what I was looking for. I had read about
pack and unpack,
but I had their functionality reversed. Your post clarified things for
me. I had to put the
bytes in in reverse order (to deal with the little-endiness of my
machine), but once I did
that I got the correct result:

$ perl -wle 'print unpack "f",chr(214).chr(174).chr(170).chr(85)'
23458486419456

Thanks again!
-larry
 
P

Peter J. Holzer

In C, I would do something akin to this:

union convert_float32 {
float f; // float view
unsigned int i; // uint32 view
} c;

unsigned char i[4];
char *q;

for (int j=0; j<4; j++) i[j] = (unsigned char)strtoul(d[j], &q, 10);
c.i = ((unsigned int)i[0] << 24) | ((unsigned int)i[1] << 16) |
((unsigned int)i[2] << 8) | (unsigned int)i[3];

and c.f would have the value I want (in this example
23458486419456.000000)

Actually it would make more sense to get rid of the intermediate step.

union convert_float32 {
float f; // float view
unsigned char i[4]; // 4 byte view
} c;

I don't think so. You are introducing an endian dependency which the
OP's code didn't have.

You are looking for the pack() and unpack() functions.

Unfortunately pack does't have a format for "single precision IEEE-754
floating point number in network byte order", so - as the OP already
found out - you either need to know the endianness of your platform, or
you need to convert from network (big endian) byte order to native byte
order first:

$fp_value = unpack('f', pack('L', unpack('N', $bytes)));

hp
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,967
Messages
2,570,148
Members
46,694
Latest member
LetaCadwal

Latest Threads

Top