假设我有一个十六进制数“4072508200000000”,我希望将它代表的浮点数(293.03173828125000)以IEEE-754双格式放入JavaScript变量中。
我可以想到一种使用一些屏蔽和调用pow()的方法,但是有一个更简单的解决方案吗?
需要客户端解决方案。
这可能会有所帮助。这是一个网站,允许您输入IEEE-754的十六进制编码,并获得尾数和指数的分析。
http://babbage.cs.qc.edu/IEEE-754/64bit.html
因为人们总是倾向于问“为什么?”,这就是原因:我正在尝试填写Google的Procol Buffers(protobuf)现有但不完整的实现。
答案 0 :(得分:10)
我不知道一个好方法。它当然可以通过艰难的方式完成,这是一个完全在JavaScript中的单精度示例:
js> a = 0x41973333
1100428083
js> (a & 0x7fffff | 0x800000) * 1.0 / Math.pow(2,23) * Math.pow(2, ((a>>23 & 0xff) - 127))
18.899999618530273
生产实现应该考虑到大多数字段都具有魔术值,通常通过为最大或最小的内容指定特殊解释来实现。因此,检测NaN
和无穷大。上面的例子应该检查底片。 (a& 0x80000000)
更新:好的,我也是双倍的。你不能直接扩展上面的技术,因为内部JS表示是一个double,因此根据它的定义,它最多可以处理长度为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>
有一些明显的子表达式可以分解,但我已经这样离开了,所以你可以看到它与格式的关系。
答案 1 :(得分:4)
DigitalRoss解决方案的快速添加,对于那些通过Google发现此页面的人来说。
除了我喜欢输入的+/- Infinity和NaN的边缘情况之外,你还需要考虑结果的符号:
s = a >> 31 ? -1 : 1
然后,您可以在最终乘法中包含s
以获得正确的结果。
我认为对于小端解决方案,您还需要反转a
和b
中的位并交换它们。
答案 2 :(得分:1)
新的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。