将具有 IEEE-754 双精度数的十六进制表示形式的字符串转换为 JavaScript 数值变量

发布于 2024-08-08 23:36:28 字数 446 浏览 5 评论 0原文

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

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

需要一个客户端解决方案。

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

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

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

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).

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

心舞飞扬 2024-08-15 23:36:28

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

好的,要执行 double 操作,您首先将低 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> 

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

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.

等风也等你 2024-08-15 23:36:28

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

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

s = a >> 31 ? -1 : 1

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

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

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.

高速公鹿 2024-08-15 23:36:28

新的类型化数组机制允许您这样做(并且可能是实现协议缓冲区的理想机制):

var buffer = new ArrayBuffer(8);
var bytes = new Uint8Array(buffer);
var doubles = new Float64Array(buffer);

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

这假设代码正在运行小端机器。
(例如:Windows或Android,而MacOS / iOS始终以大端运行)。

了解更多:

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);

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

This assumes the code is running a little-endian machine.
(eg: Windows or Android, whereas MacOS / iOS are always running in big-endian).

Read more:

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文