JavaScript-以干净的方式将字节转换为浮点

JavaScript-以干净的方式将字节转换为浮点,javascript,floating-point,buffer,converters,Javascript,Floating Point,Buffer,Converters,我最近发现我可以将Float32转换为表示它的字节数组-如下所示: let number = Math.PI; let bytes = new Uint8Array(new Float32Array([number]).buffer); // [219, 15, 73, 64] 有没有办法以干净的方式将字节转换回Float32? 有没有办法将字节转换回Float32 你不需要转换它,它已经在那里了!您只需要从float32视图中读取它。但是,在您的示例中,您没有保存对float32视图的引用

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

let number = Math.PI;
let bytes = new Uint8Array(new Float32Array([number]).buffer); // [219, 15, 73, 64]
有没有办法以干净的方式将
字节
转换回Float32?

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

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

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

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

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格式。

天哪,这太酷了,谢谢。将float32array视为缓冲区的简单视图确实有帮助。关于IEEE 754,大约一年前,我实际上用它来实现我自己的“浮点到字节”算法,但现在我发现这可以通过本机实现(可能更快),我想我会用它来代替。:)很高兴它起到了作用,您将自己的实现作为一个学习练习真的很好:)当您开始探索浮点格式的局限性和陷阱时,您会惊讶地发现,对浮点格式的正确理解是多么不寻常,它也会无限复杂!一个人永远不可能真正声称自己知道浮点数学的所有含义。哈哈,真的!但是,是的,我建议大家至少检查一下引擎盖下的格式,因为它基本上对任何编程语言都是绝对必要的。另外,关于你的帖子,我认为Math.PI的Float32表示形式是3.1415927410125732,而不是3.141592653589793,因为有些精度丢失了。啊哈,是的,你发现了我的懒拷贝粘贴。固定的。尽管二进制有效位较短,但f32十进制有效位却显得较长,这也有点令人困惑(因为它在打印为十进制之前是如何转换为f64的)。是的,这些事情很奇怪-小心处理;这能回答你的问题吗?