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.
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).
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.
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
b and swap them.
The new Typed Arrays mechanism allows you to do this (and is probably an ideal mechanism for implementing protocol buffers):
var buffer = new ArrayBuffer(8); var bytes = new Uint8Array(buffer); var doubles = new Float64Array(buffer); // not supported in Chrome bytes = 0x40; // Load the hex string "40 72 50 82 00 00 00 00" bytes = 0x72; bytes = 0x50; bytes = 0x82; bytes = 0x00; bytes = 0x00; bytes = 0x00; bytes = 0x00; my_double = doubles; document.write(my_double); // 293.03173828125
This assumes a little-endian machine.
Unfortunately Chrome does not have
Float64Array, although it does have
Float32Array. The above example does work in Firefox 4.0.1.
©2020 All rights reserved.