views:

641

answers:

2

Suppose I have a hex number "4072508200000000" and I want the floating point number that it represents (293.03173828125000) in IEEE-754 double format to be put into a JavaScript variable.

I can think of a way that uses some masking and a call to pow(), but is there a simpler solution?

A client-side solution is needed.

This may help. It's a website that lets you enter a hex encoding of an IEEE-754 and get an analysis of mantissa and exponent.

http://babbage.cs.qc.edu/IEEE-754/64bit.html

Because people always tend to ask "why?," here's why: I'm trying to fill out an existing but incomplete implementation of Google's Procol Buffers (protobuf).

+5  A: 

I don't know of a good way. It certainly can be done the hard way, here is a single-precision example totally within JavaScript:

js> a = 0x41973333
1100428083
js> (a & 0x7fffff | 0x800000) * 1.0 / Math.pow(2,23) * Math.pow(2,  ((a>>23 & 0xff) - 127))
18.899999618530273

A production implementation should consider that most of the fields have magic values, typically implemented by specifying a special interpretation for what would have been the largest or smallest. So, detect NaNs and infinities. The above example should be checking for negatives. (a & 0x80000000)

Update: Ok, I've got it for double's, too. You can't directly extend the above technique because the internal JS representation is a double, and so by its definition it can handle at best a bit string of length 52, and it can't shift by more than 32 at all.

Ok, to do double you first chop off as a string the low 8 digits or 32 bits; process them with a separate object. Then:

js> a = 0x40725082      
1081233538
js> (a & 0xfffff | 0x100000) * 1.0 / Math.pow(2, 52 - 32) * Math.pow(2, ((a >> 52 - 32 & 0x7ff) - 1023))
293.03173828125
js>

I kept the above example because it's from the OP. A harder case is when the low 32-bits have a value. Here is the conversion of 0x40725082deadbeef, a full-precision double:

js> a = 0x40725082
1081233538
js> b = 0xdeadbeef
3735928559
js> e = (a >> 52 - 32 & 0x7ff) - 1023
8
js> (a & 0xfffff | 0x100000) * 1.0 / Math.pow(2,52-32) * Math.pow(2, e) +          
     b * 1.0 / Math.pow(2, 52) * Math.pow(2, e)
293.0319506442019
js>

There are some obvious subexpressions you can factor out but I've left it this way so you can see how it relates to the format.

DigitalRoss
My last example does agree with your linked site for 0x40725082deadbeef.
DigitalRoss
Very nice. Thanks.
Nosredna
+1  A: 

A quick addition to DigitalRoss' solution, for those finding this page via Google as I did.

Apart from the edge cases for +/- Infinity and NaN, which I'd love input on, you also need to take into account the sign of the result:

s = a >> 31 ? -1 : 1

You can then include s in the final multiplication to get the correct result.

I think for a little-endian solution you'll also need to reverse the bits in a and b and swap them.

RandomEtc