【问题标题】:JavaScript - Convert bytes into float in a clean wayJavaScript - 以干净的方式将字节转换为浮点数
【发布时间】:2018-08-30 23:16:16
【问题描述】:

我最近发现我可以将 Float32 转换为代表它的字节数组 - 例如:

let number = Math.PI;
let bytes = new Uint8Array(new Float32Array([number]).buffer); // [219, 15, 73, 64]

有没有办法以干净的方式将bytes 转换回 Float32?

【问题讨论】:

标签: javascript floating-point buffer converters


【解决方案1】:

有没有办法将字节转换回 Float32

你不需要转换它,它已经存在了!你只需要从 float32 视图中读取它。但是在您的示例中,您没有保存对 float32 视图的引用...

类型化数组的工作方式与 JavaScript 中的其他数字非常不同。关键是要独立考虑缓冲区和视图——也就是说,Float32Array 和 Uint8Array 只是 views 进入缓冲区(缓冲区只是一个固定大小的连续内存块,这就是为什么类型化数组是这么快)。

在您的示例中,当您调用 new Float32Array 时,您向它传递了一个带有单个数字的数组来初始化它,但您没有传递一个缓冲区,这会导致它为您创建一个适当长度的缓冲区(4字节)。当您调用new Uint8Array 时,您改为将缓冲区传递给它,这不会导致它仅复制缓冲区,而是实际上直接使用它。下面的示例与您的示例等价,但保留了所有引用并使上述断言更加明显:

const number = Math.PI

const buffer = new ArrayBuffer(4);
const f32 = new Float32Array(buffer); // [0]
const ui8 = new Uint8Array(buffer); // [0, 0, 0, 0]

f32[0] = number;
f32 // [3.1415927410125732]
ui8 // [219, 15, 73, 64]

ui8[3] = 1;
f32 // [3.6929245196445856e-38]
ui8 // [219, 15, 73, 1]

如您所见,无需在上面“转换”,因为两个视图共享相同的缓冲区,因此通过一个视图进行的任何更改都可以立即在另一个视图中使用。

这实际上是使用和理解浮点格式的好方法。还使用ui8[i].toString(2) 获取原始二进制文件并使用ui8[i] = parseInt('01010101', 2) 为i 为0-3 的每个字节设置原始二进制文件。请注意,您不能通过 f32 视图设置原始二进制文件,因为它会以数字方式解释您的数字并将其分解为有效数和指数,但是您可能希望这样做以查看数字二进制文件如何转换为 float32 格式。

【讨论】:

  • 天哪,这太酷了,谢谢。将 Float32Arrays 视为对缓冲区的简单视图确实有帮助。关于 IEEE 754,我实际上在一年前使用它来实现我自己的“浮点到字节”算法,但现在我发现这可以在本地完成(并且可能更快),我想我会使用它来代替。 :)
  • 很高兴它有帮助,您将自己的实现作为学习练习真是太好了 :) 您会惊讶于对浮点格式的体面理解是多么罕见,当您开始探索它的局限性和陷阱!一个人永远无法真正声称了解浮点数学的所有含义。
  • 哈哈,确实!但是,是的,我建议每个人至少检查一下引擎盖下的格式,因为基本上它对于任何编程语言都是绝对必要的。另外,关于您的帖子的一件事,我认为 Math.PI 的 Float32 表示是 3.1415927410125732,而不是 3.141592653589793 - 因为丢失了一些精度。
  • 啊,是的,你发现了我的懒惰复制粘贴。固定的。尽管二进制有效数字更短,但 f32 十进制有效数字似乎更长,这也有点令人困惑(因为在打印为十进制之前它是如何转换为 f64 的)。
  • 是的,那些东西很奇怪——小心处理。 ;P
猜你喜欢
  • 2022-11-13
  • 2022-11-12
  • 1970-01-01
  • 2021-08-09
  • 2010-09-05
  • 2015-08-25
  • 1970-01-01
相关资源
最近更新 更多