Converting 8 bytes to a Float


#1

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

thanks for any help,

~harris


#2

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

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

Mike S. removed_email_address@domain.invalid
http://www.stok.ca/~mike/

The “`Stok’ disclaimers” apply.


#3

Harris R. 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’)


#4

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 H. removed_email_address@domain.invalid
To: ruby-talk ML removed_email_address@domain.invalid
Sent: Thursday, June 8, 2006 8:26:52 PM
Subject: Re: Converting 8 bytes to a Float

Harris R. 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’)


#5

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

bytes[6] = 0

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 S. removed_email_address@domain.invalid
http://www.stok.ca/~mike/

The “`Stok’ disclaimers” apply.


#6

On Fri, 9 Jun 2006, Harris R. wrote:

bytes[7] = 0

thanks,

~harris

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


#7

Harris R. wrote:

bytes[7] = 0

I was wrong about pack. String#unpack is what you need, as others have
suggested.


#8

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 S. removed_email_address@domain.invalid
To: ruby-talk ML removed_email_address@domain.invalid
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 R. wrote:

bytes[6] = 0

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 S. removed_email_address@domain.invalid
http://www.stok.ca/~mike/

The “`Stok’ disclaimers” apply.


#9

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 S. removed_email_address@domain.invalid
To: ruby-talk ML removed_email_address@domain.invalid
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 R. wrote:

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 http://en.wikipedia.org/wiki/Endian for more background.

Hope this helps,

Mike


Mike S. removed_email_address@domain.invalid
http://www.stok.ca/~mike/

The “`Stok’ disclaimers” apply.


#10

On 6/9/06, Harris R. removed_email_address@domain.invalid 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


#11

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

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 http://en.wikipedia.org/wiki/Endian for more background.

Hope this helps,

Mike


Mike S. removed_email_address@domain.invalid
http://www.stok.ca/~mike/

The “`Stok’ disclaimers” apply.


#12

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 L. removed_email_address@domain.invalid
To: ruby-talk ML removed_email_address@domain.invalid
Sent: Friday, June 9, 2006 5:55:56 PM
Subject: Re: Converting a Float back to bytes

On 6/9/06, Harris R. removed_email_address@domain.invalid 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


#13

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:

http://en.wikipedia.org/wiki/IEEE_754

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

}


#14

Harris,

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

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:

http://en.wikipedia.org/wiki/Top-posting

I shall now become an observer again :slight_smile:

Cheers,
Phil


#15

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

I think a result of this work I am doing should be a general

Mike… thanks for the tip. My mileage is varying though… here

Hope this helps,

Mike


Mike S. removed_email_address@domain.invalid
http://www.stok.ca/~mike/

The “`Stok’ disclaimers” apply.

[21.0].pack(“D”) no?