9

假设我有一个十六进制数“4072508200000000”,并且我希望将其代表的浮点数 (293.03173828125000) 以 IEEE-754 双精度格式放入 JavaScript 变量中。

我可以想到一种使用一些掩码和调用 pow() 的方法,但是有没有更简单的解决方案?

需要客户端解决方案。

这可能会有所帮助。这是一个网站,可让您输入 IEEE-754 的十六进制编码并分析尾数和指数。

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

因为人们总是倾向于问“为什么?”,原因如下:我正在尝试填写 Google 的 Procol Buffers (protobuf) 的现有但不完整的实现。

4

3 回答 3

11

不知道有什么好办法。它当然可以通过困难的方式完成,这是一个完全在 JavaScript 中的单精度示例:

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

生产实现应该考虑到大多数字段都有神奇的值,通常通过为最大或最小的内容指定特殊解释来实现。因此,检测NaNs 和无穷大。上面的例子应该检查否定。(a & 0x80000000)

更新:好的,我也有双份的。您不能直接扩展上述技术,因为内部 JS 表示是双精度的,因此根据它的定义,它最多可以处理长度为 52 的位串,并且它的移位根本不能超过 32。

好的,要加倍,您首先将低 8 位或 32 位作为字符串切掉;用单独的对象处理它们。然后:

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> 

我保留了上面的示例,因为它来自 OP。更难的情况是低 32 位有值。这是 0x40725082deadbeef 的转换,一个全精度双精度:

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> 

您可以排除一些明显的子表达式,但我将其保留为这种方式,以便您了解它与格式的关系。

于 2009-10-20T23:38:16.703 回答
4

DigitalRoss 解决方案的快速补充,适用于像我一样通过 Google 找到此页面的人。

除了我喜欢输入的 +/- Infinity 和 NaN 的边缘情况之外,您还需要考虑结果的符号:

s = a >> 31 ? -1 : 1

然后,您可以包含s在最终的乘法中以获得正确的结果。

我认为对于小端解决方案,您还需要反转位ab交换它们。

于 2009-11-22T08:29:48.593 回答
2

新的Typed Arrays机制允许您这样做(并且可能是实现协议缓冲区的理想机制):

var buffer = new ArrayBuffer(8);
var bytes = new Uint8Array(buffer);
var doubles = new Float64Array(buffer); // not supported in Chrome

bytes[7] = 0x40; // Load the hex string "40 72 50 82 00 00 00 00" 
bytes[6] = 0x72;
bytes[5] = 0x50;
bytes[4] = 0x82;
bytes[3] = 0x00;
bytes[2] = 0x00;
bytes[1] = 0x00;
bytes[0] = 0x00;

my_double = doubles[0];

document.write(my_double);  // 293.03173828125

这假设一个小端机器。

不幸的是 Chrome 没有Float64Array,虽然它有Float32Array。上面的示例在 Firefox 4.0.1 中确实有效。

于 2011-06-15T16:47:51.957 回答