Forum: Ruby Converting 8 bytes to a Float

Announcement (2017-05-07): www.ruby-forum.com is now read-only since I unfortunately do not have the time to support and maintain the forum any more. Please see rubyonrails.org/community and ruby-lang.org/en/community for other Rails- und Ruby-related community platforms.
Harris R. (Guest)
on 2006-06-09 04:23
(Received via mailing list)
What is the quickest way to convert 8 bytes to a Float object?

thanks for any help,

~harris
Mike S. (Guest)
on 2006-06-09 04:27
(Received via mailing list)
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.
Timothy H. (Guest)
on 2006-06-09 04:30
(Received via mailing list)
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')
Harris R. (Guest)
on 2006-06-09 04:48
(Received via mailing list)
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')
Mike S. (Guest)
on 2006-06-09 04:58
(Received via mailing list)
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 ;-) .  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.
unknown (Guest)
on 2006-06-09 05:10
(Received via mailing list)
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
Timothy H. (Guest)
on 2006-06-09 05:19
(Received via mailing list)
Harris R. wrote:
> bytes[7] = 0
>
I was wrong about pack. String#unpack is what you need, as others have
suggested.
Harris R. (Guest)
on 2006-06-09 06:42
(Received via mailing list)
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 ;-) .  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.
Mike S. (Guest)
on 2006-06-09 06:52
(Received via mailing list)
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.
Harris R. (Guest)
on 2006-06-10 01:45
(Received via mailing list)
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.
Ryan L. (Guest)
on 2006-06-10 01:58
(Received via mailing list)
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
Harris R. (Guest)
on 2006-06-10 02:24
(Received via mailing list)
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
Charlie S. (Guest)
on 2006-06-10 03:56
(Received via mailing list)
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
   }
Logan C. (Guest)
on 2006-06-11 23:27
(Received via mailing list)
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?
Phil J. (Guest)
on 2006-06-18 21:48
(Received via mailing list)
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 :)

Cheers,
Phil
This topic is locked and can not be replied to.