Converting 8 bytes to a Float

What is the quickest way to convert 8 bytes to a Float object?

thanks for any help,

~harris

Probably String#unpack where the string contains the 8 bytes. You will have to pick the right one of the template directive depending on the byte order of your data.

Mike

···

On 8-Jun-06, at 8:20 PM, Harris Reynolds wrote:

What is the quickest way to convert 8 bytes to a Float object?

thanks for any help,

~harris

--

Mike Stok <mike@stok.ca>
http://www.stok.ca/~mike/

The "`Stok' disclaimers" apply.

Harris Reynolds wrote:

What is the quickest way to convert 8 bytes to a Float object?
thanks for any help,
~harris
  

ri Array#pack

flt = arr.pack('D')

I am still not getting the results I am looking for hacking around with the couple suggestions I received. Here is an example:

bytes = Array.new(8)
bytes[0] = 64
bytes[1] = 53
bytes[2] = 0
bytes[3] = 0
bytes[4] = 0
bytes[5] = 0
bytes[6] = 0
bytes[7] = 0

Calling:

binary_string = bytes.pack('D')

returns a binary string, but not the float which should be 21.0; if I turn around and call

binary_string.unpack('d'), I end up with the original bytes.

It is turning out that getting from bytes to a Float object is a bit painful. Is there something easy I am missing?

thanks,

~harris

···

----- Original Message ----
From: Timothy Hunter <TimHunter@nc.rr.com>
To: ruby-talk ML <ruby-talk@ruby-lang.org>
Sent: Thursday, June 8, 2006 8:26:52 PM
Subject: Re: Converting 8 bytes to a Float

Harris Reynolds wrote:

What is the quickest way to convert 8 bytes to a Float object?

thanks for any help,

~harris
  

ri Array#pack

flt = arr.pack('D')

You should be using unpack :wink: . In irb:

ratdog:~ mike$ irb
irb(main):001:0> s = ""
=> ""
irb(main):002:0> s << 64 << 53 <<"\0" * 6
=> "@5\000\000\000\000\000\000"
irb(main):003:0> s.unpack('D')
=> [21.0]

Mike

···

On 8-Jun-06, at 8:47 PM, Harris Reynolds wrote:

I am still not getting the results I am looking for hacking around with the couple suggestions I received. Here is an example:

bytes = Array.new(8)
bytes[0] = 64
bytes[1] = 53
bytes[2] = 0
bytes[3] = 0
bytes[4] = 0
bytes[5] = 0
bytes[6] = 0
bytes[7] = 0

Calling:

binary_string = bytes.pack('D')

returns a binary string, but not the float which should be 21.0; if I turn around and call

binary_string.unpack('d'), I end up with the original bytes.

It is turning out that getting from bytes to a Float object is a bit painful. Is there something easy I am missing?

--

Mike Stok <mike@stok.ca>
http://www.stok.ca/~mike/

The "`Stok' disclaimers" apply.

you just need to pack them into a binary string period, since you have the
bytes you don't need to pack them as a float, eg:

   harp:~ > cat a.rb
   f = 21
   buf = [f].pack 'D'
   bytes = buf.unpack 'c*'
   p bytes

   buf = bytes.pack 'c*'
   f = buf.unpack('D').first
   p f

   harp:~ > ruby a.rb
   [0, 0, 0, 0, 0, 0, 53, 64]
   21.0

regards.

-a

···

On Fri, 9 Jun 2006, Harris Reynolds wrote:

I am still not getting the results I am looking for hacking around with the couple suggestions I received. Here is an example:

bytes = Array.new(8)
bytes[0] = 64
bytes[1] = 53
bytes[2] = 0
bytes[3] = 0
bytes[4] = 0
bytes[5] = 0
bytes[6] = 0
bytes[7] = 0

Calling:

binary_string = bytes.pack('D')

returns a binary string, but not the float which should be 21.0; if I turn around and call

binary_string.unpack('d'), I end up with the original bytes.

It is turning out that getting from bytes to a Float object is a bit painful. Is there something easy I am missing?

thanks,

~harris

--
suffering increases your inner strength. also, the wishing for suffering
makes the suffering disappear.
- h.h. the 14th dali lama

Harris Reynolds wrote:

I am still not getting the results I am looking for hacking around with the couple suggestions I received. Here is an example:
bytes = Array.new(8)
bytes[0] = 64
bytes[1] = 53
bytes[2] = 0
bytes[3] = 0
bytes[4] = 0
bytes[5] = 0
bytes[6] = 0
bytes[7] = 0
Calling:
binary_string = bytes.pack('D')
returns a binary string, but not the float which should be 21.0; if I turn around and call
binary_string.unpack('d'), I end up with the original bytes.
It is turning out that getting from bytes to a Float object is a bit painful. Is there something easy I am missing?
  
I was wrong about pack. String#unpack is what you need, as others have suggested.

Mike... thanks for the tip. My mileage is varying though... here is the same irb session on my machine:

irb(main):004:0> s = ""
=> ""
irb(main):005:0> s << 64 << 53 << "\0" * 6
=> "@5\000\000\000\000\000\000"
irb(main):006:0> s.unpack('D')
=> [6.73510288410787e-320]

I'm not getting the clean result for some reason.

~harris

···

----- Original Message ----
From: Mike Stok <mike@stok.ca>
To: ruby-talk ML <ruby-talk@ruby-lang.org>
Sent: Thursday, June 8, 2006 8:57:06 PM
Subject: Re: Converting 8 bytes to a Float

On 8-Jun-06, at 8:47 PM, Harris Reynolds wrote:

I am still not getting the results I am looking for hacking around
with the couple suggestions I received. Here is an example:

bytes = Array.new(8)
bytes[0] = 64
bytes[1] = 53
bytes[2] = 0
bytes[3] = 0
bytes[4] = 0
bytes[5] = 0
bytes[6] = 0
bytes[7] = 0

Calling:

binary_string = bytes.pack('D')

returns a binary string, but not the float which should be 21.0; if
I turn around and call

binary_string.unpack('d'), I end up with the original bytes.

It is turning out that getting from bytes to a Float object is a
bit painful. Is there something easy I am missing?

You should be using unpack :wink: . In irb:

ratdog:~ mike$ irb
irb(main):001:0> s = ""
=> ""
irb(main):002:0> s << 64 << 53 <<"\0" * 6
=> "@5\000\000\000\000\000\000"
irb(main):003:0> s.unpack('D')
=> [21.0]

Mike

--

Mike Stok <mike@stok.ca>
http://www.stok.ca/~mike/

The "`Stok' disclaimers" apply.

I'm on a PowerPC, and you're probably on an x86. Our endian-ness is different.

D uses native format to unpack the bytes, if your bytes are laid out the way you said they are then you probably want to use G which is specifically "big endian".

See Endian - Wikipedia for more background.

Hope this helps,

Mike

···

On 8-Jun-06, at 10:39 PM, Harris Reynolds wrote:

Mike... thanks for the tip. My mileage is varying though... here is the same irb session on my machine:

irb(main):004:0> s = ""
=> ""
irb(main):005:0> s << 64 << 53 << "\0" * 6
=> "@5\000\000\000\000\000\000"
irb(main):006:0> s.unpack('D')
=> [6.73510288410787e-320]

I'm not getting the clean result for some reason.

--
Mike Stok <mike@stok.ca>
http://www.stok.ca/~mike/

The "`Stok' disclaimers" apply.

This is good stuff. I am now getting the correct Float object (21.0) from a string of bytes ("@5\000\000\000\000\000\000"). Now... here is a question... is there an easy way to go from the Float back to bytes. This seems like it may be much more difficult.

something like this...

float_object = 21.0
bytes = SOME_API_HERE.convert(float_object)

I think a result of this work I am doing should be a general purpose BitConverter class similar to what .Net offers. This would make working with binary data in Ruby much less painful.

thanks for any help,

~harris

p.s. Mike... thanks a bunch for the help on going from Bytes to a Float!!! I owe you... are you going to be at RailsConf?

···

----- Original Message ----
From: Mike Stok <mike@stok.ca>
To: ruby-talk ML <ruby-talk@ruby-lang.org>
Sent: Thursday, June 8, 2006 10:49:36 PM
Subject: Re: Converting 8 bytes to a Float

On 8-Jun-06, at 10:39 PM, Harris Reynolds wrote:

Mike... thanks for the tip. My mileage is varying though... here
is the same irb session on my machine:

irb(main):004:0> s = ""
=> ""
irb(main):005:0> s << 64 << 53 << "\0" * 6
=> "@5\000\000\000\000\000\000"
irb(main):006:0> s.unpack('D')
=> [6.73510288410787e-320]

I'm not getting the clean result for some reason.

I'm on a PowerPC, and you're probably on an x86. Our endian-ness is
different.

D uses native format to unpack the bytes, if your bytes are laid out
the way you said they are then you probably want to use G which is
specifically "big endian".

See Endian - Wikipedia for more background.

Hope this helps,

Mike

--
Mike Stok <mike@stok.ca>
http://www.stok.ca/~mike/

The "`Stok' disclaimers" apply.

Hi Harris,

Keep in mind for things like this you always have the method pair
Array#pack and String#unpack:

C:\P4WS>irb
irb(main):001:0> f = 21.0
=> 21.0
irb(main):002:0> b = [f].pack("D")
=> "\000\000\000\000\000\0005@"
irb(main):003:0> b.unpack("D")
=> [21.0]

Ryan

···

On 6/9/06, Harris Reynolds <hreynolds2@yahoo.com> wrote:

This is good stuff. I am now getting the correct Float object (21.0) from a string of bytes
("@5\000\000\000\000\000\000"). Now... here is a question... is there an easy way to go
from the Float back to bytes. This seems like it may be much more difficult.

something like this...

float_object = 21.0
bytes = SOME_API_HERE.convert(float_object)

Here are two functions in javascript that convert a double to and from a hex encoded byte stream. They are part of a larger class but should more or less make sense.

Some notes:

* this is for doubles, ie 64-bit values, that are IEEE 754 encoded
* this.hex is a hex string
* WKB.WKB_XDR is big endian
* WKB.WKB_NDR is little endian

There is a good article on wikipedia about this:

Charlie

···

---------------------

readDouble: function()
{
    // Read IEEE 754 64-bit (8 bytes) double
     var doubleHex = this.hex.slice(this.pos, this.pos + 16)
     this.pos += 16

     if (this.byteOrder == Geometry.WKB.WKB_NDR)
       doubleHex = Geometry.WKB.swapEndian(doubleHex)

     // get first 12 bits
     var signExponentHex = doubleHex.slice(0, 3)
     var signExponent = parseInt(signExponentHex, 16)

     // get sign and exponent
     var sign = signExponent & 0x800
     var exponent = signExponent & 0x7FF

     // get fraction which is 52 bits
     var fractionHex = doubleHex.slice(3, 16)
     var fraction = parseInt(fractionHex, 16)

     if (exponent == 2047 && fraction != 0)
     {
       // NaN - Not a number
       value = Number.NaN
     }
     else if (exponent == 2047 && fraction == 0 && sign == 1)
     {
       // Negative infinity
       value = Number.NEGATIVE_INFINITY
     }
     else if (exponent == 2047 && fraction == 0 && sign == 0)
     {
       // Positive infinity
       value = Number.POSITIVE_INFINITY
     }
     else if (exponent > 0 && exponent < 2047)
     {
       // Most significant byte should be 1 in normalized form
       fraction += Math.pow(2,52)
       value = fraction * Math.pow(2, exponent - 1023 - 52)
       if (sign)
         value = -value
     }
     else if (exponent == 0 && fraction != 0)
     {
       // Denormal number
       value = fraction * Math.pow(2, -1022 - 52);
       if (sign)
         value = -value
     }
     else if (exponent == 0 && fraction == 0 && sign == 1)
     {
       // Negative zero
       value = 0
     }
     else if (exponent == 0 && fraction == 0 && sign == 0)
     {
       // Positive zero
       value = 0
     }
     else
     {
       throw new Error('Could not parse floating point number')
     }

     return value
   }

writeDouble: function(value)
{
     // get integer and fraction
     var positiveValue = Math.abs(value)
     var integer = Math.floor(positiveValue)
     var fraction = positiveValue - integer

     var intBin = integer.toString(2)
     // convert to fraction, then remove leading "0."
     var fractionBin = fraction.toString(2).slice(2)

     var exponent = null
     var significandBin = null

     if (integer >= 1)
     {
       // Figure out exponent - 1023 is the bias bias
       exponent = 1023 + intBin.length - 1
       significandBin = intBin.slice(1) + fractionBin
     }
     else
     {
       var index = fractionBin.search(/1/)

       if (index == -1)
       {
         exponent = 0
         significandBin = "0"
       }
       else
       {
         // figure out exponent - 1023 is the bias bias
         exponent = 1023 - index - 1
         significandBin = fractionBin.slice(index + 1)
       }
     }

     // write sign bit
     if (value < 0)
       bin = "1"
    else
       bin = "0"

     // write exponent which is 11 bits
     bin += this.padLeft(exponent.toString(2), 11)
     // write the significand which is 52 bits
     bin += this.padRight(significandBin, 52)

     // Now convert to hex one byte at a time
     var value = ""
     for (var i=0; i<8; i++)
     {
       var temp = parseInt(bin.slice(i*8, i*8+8),2)
       // Geos only accepts hex values in upper case
       var upper = temp.toString(16).toUpperCase()
       value += this.padLeft(upper.toString(16),2)
     }

     if (this.byteOrder == Geometry.WKB.WKB_NDR)
       value = Geometry.WKB.swapEndian(value)

     this.hex += value
   }

Harris Reynolds wrote:

This is good stuff. I am now getting the correct Float object (21.0) from a string of bytes ("@5\000\000\000\000\000\000"). Now... here is a question... is there an easy way to go from the Float back to bytes. This seems like it may be much more difficult.
something like this...
float_object = 21.0
bytes = SOME_API_HERE.convert(float_object)
I think a result of this work I am doing should be a general purpose BitConverter class similar to what .Net offers. This would make working with binary data in Ruby much less painful.
thanks for any help,
~harris
p.s. Mike... thanks a bunch for the help on going from Bytes to a Float!!! I owe you... are you going to be at RailsConf?

----- Original Message ----
From: Mike Stok <mike@stok.ca>
To: ruby-talk ML <ruby-talk@ruby-lang.org>
Sent: Thursday, June 8, 2006 10:49:36 PM
Subject: Re: Converting 8 bytes to a Float

On 8-Jun-06, at 10:39 PM, Harris Reynolds wrote:

Mike... thanks for the tip. My mileage is varying though... here is the same irb session on my machine:

irb(main):004:0> s = ""
=> ""
irb(main):005:0> s << 64 << 53 << "\0" * 6
=> "@5\000\000\000\000\000\000"
irb(main):006:0> s.unpack('D')
=> [6.73510288410787e-320]

I'm not getting the clean result for some reason.

I'm on a PowerPC, and you're probably on an x86. Our endian-ness is different.

D uses native format to unpack the bytes, if your bytes are laid out the way you said they are then you probably want to use G which is specifically "big endian".

See Endian - Wikipedia for more background.

Hope this helps,

Mike

[21.0].pack("D") no?

···

On Jun 9, 2006, at 5:44 PM, Harris Reynolds wrote:

This is good stuff. I am now getting the correct Float object (21.0) from a string of bytes ("@5\000\000\000\000\000\000"). Now... here is a question... is there an easy way to go from the Float back to bytes. This seems like it may be much more difficult.

something like this...

float_object = 21.0
bytes = SOME_API_HERE.convert(float_object)

I think a result of this work I am doing should be a general purpose BitConverter class similar to what .Net offers. This would make working with binary data in Ruby much less painful.

thanks for any help,

~harris

p.s. Mike... thanks a bunch for the help on going from Bytes to a Float!!! I owe you... are you going to be at RailsConf?

----- Original Message ----
From: Mike Stok <mike@stok.ca>
To: ruby-talk ML <ruby-talk@ruby-lang.org>
Sent: Thursday, June 8, 2006 10:49:36 PM
Subject: Re: Converting 8 bytes to a Float

On 8-Jun-06, at 10:39 PM, Harris Reynolds wrote:

Mike... thanks for the tip. My mileage is varying though... here
is the same irb session on my machine:

irb(main):004:0> s = ""
=> ""
irb(main):005:0> s << 64 << 53 << "\0" * 6
=> "@5\000\000\000\000\000\000"
irb(main):006:0> s.unpack('D')
=> [6.73510288410787e-320]

I'm not getting the clean result for some reason.

I'm on a PowerPC, and you're probably on an x86. Our endian-ness is
different.

D uses native format to unpack the bytes, if your bytes are laid out
the way you said they are then you probably want to use G which is
specifically "big endian".

See Endian - Wikipedia for more background.

Hope this helps,

Mike

--
Mike Stok <mike@stok.ca>
Mike Stok

The "`Stok' disclaimers" apply.

Thanks Ryan... I had orignally thought this shouldn't be any harder than calling unpack coming from the oposite direction; nonetheless it didn't dawn on me to simply stuff the float into an array and call pack.

Gotta love learning a new language! Thanks,

~harris

···

----- Original Message ----
From: Ryan Leavengood <leavengood@gmail.com>
To: ruby-talk ML <ruby-talk@ruby-lang.org>
Sent: Friday, June 9, 2006 5:55:56 PM
Subject: Re: Converting a Float back to bytes

On 6/9/06, Harris Reynolds <hreynolds2@yahoo.com> wrote:

This is good stuff. I am now getting the correct Float object (21.0) from a string of bytes
("@5\000\000\000\000\000\000"). Now... here is a question... is there an easy way to go
from the Float back to bytes. This seems like it may be much more difficult.

something like this...

float_object = 21.0
bytes = SOME_API_HERE.convert(float_object)

Hi Harris,

Keep in mind for things like this you always have the method pair
Array#pack and String#unpack:

C:\P4WS>irb
irb(main):001:0> f = 21.0
=> 21.0
irb(main):002:0> b = [f].pack("D")
=> "\000\000\000\000\000\0005@"
irb(main):003:0> b.unpack("D")
=> [21.0]

Ryan

Harris,

Thanks Ryan... I had orignally thought this shouldn't be any harder than
calling unpack coming from the oposite direction; nonetheless it didn't
dawn on me to simply stuff the float into an array and call pack.

Gotta love learning a new language! Thanks,

Usually I would keep my mouth shut about this sort of thing but I can't help
it on this occasion. The message I'm replying to is practically unreadable
thanks to the top posting. Please read and consider this:

I shall now become an observer again :slight_smile:

Cheers,
Phil

···

On Sat, Jun 10, 2006 at 07:22:07 +0900, Harris Reynolds wrote: