【问题标题】:Convert a string with a hex representation of an IEEE-754 double into JavaScript numeric variable将具有 IEEE-754 双精度的十六进制表示的字符串转换为 JavaScript 数值变量
【发布时间】:2010-12-08 12:52:04
【问题描述】:

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

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

需要客户端解决方案。

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

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

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

【问题讨论】:

  • 就我个人而言,我会先用正则表达式将十六进制值分割成单独的部分。然后,我会将它们评估为整数,最后我会尝试将它们转回浮点数。这似乎是一件很棘手的事情,因为您必须这样做,以便 Javascript 运行时不会在此过程中丢失任何位。
  • 为了获得最大的可移植性,您应该考虑 IEEE-754 双精度可以是大端或小端。如果您知道十六进制输入使用哪种约定,则使用 pow() 的客户端解决方案应该是可移植的。如果您决定使用某种类型的双关语方法,则必须首先检查双精度的客户端平台字节序。
  • @Jim Lewis:我确实有一个标志可以告诉我大端或小端。
  • @Pointy,但是如何“把它们变成一个浮点数”。不做a*pow(2^b)是不行的,还是有别的办法?
  • @jim Lewis。我确实在寻找一种类型双关语的方法,但想不出 JavaScript 会允许它的方式。

标签: javascript double hex ieee-754


【解决方案1】:

我不知道有什么好方法。它当然可以通过困难的方式完成,这是一个完全在 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 表示是一个 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> 

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

【讨论】:

  • 我的最后一个例子确实同意你的链接网站 0x40725082deadbeef。
  • 为什么当 a = 0 时这段代码(倒数第二个示例)返回 1.1125369292536007e-308
【解决方案2】:

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

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

s = a >> 31 ? -1 : 1

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

我认为对于 little-endian 解决方案,您还需要反转 ab 中的位并交换它们。

【讨论】:

    【解决方案3】:

    新的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 中确实有效。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-09-18
      • 2014-06-18
      • 1970-01-01
      • 1970-01-01
      • 2013-10-04
      • 2011-11-01
      • 1970-01-01
      • 2014-05-05
      相关资源
      最近更新 更多