在 JS 中读/写浮点字节数

IT技术 javascript serialization floating-point math ieee-754
2021-01-15 09:29:23

有什么办法可以读取 JS 中浮点值的字节吗?我需要的是将原始 FLOAT 或 DOUBLE 值写入我需要制作的某种二进制格式,那么有没有办法获得逐字节的 IEEE 754 表示?当然还有同样的写作问题。

6个回答

您可以使用类型化数组来做到这一点

var buffer = new ArrayBuffer(4);
var intView = new Int32Array(buffer);
var floatView = new Float32Array(buffer);

floatView[0] = Math.PI
console.log(intView[0].toString(2)); //bits of the 32 bit float

或者另一种方式:

var view = new DataView(new ArrayBuffer(4));
view.setFloat32(0, Math.PI);
console.log(view.getInt32(0).toString(2)); //bits of the 32 bit float

虽然不确定浏览器支持是什么样的

看起来您可以使用 a Uint8Array(至少在 Chrome 中)而不是Int32Array更轻松地获取单个字节
2021-03-17 09:29:23
请注意,这不是在IE9支持!
2021-03-23 09:29:23
@bryc,Netscape Navigator 支持也不完美。
2021-04-02 09:29:23
很酷,在 Javascript 中Double调用Float64TIL 我一直在寻找DoubleArray- 无济于事 - 但Float64Array存在并且对我有用
2021-04-04 09:29:23

我已经创建了应该更快一点的 Milos 解决方案的扩展,假设 TypedArrays 当然不是一个选项(在我的情况下,我正在使用它们不可用的环境):

function Bytes2Float32(bytes) {
    var sign = (bytes & 0x80000000) ? -1 : 1;
    var exponent = ((bytes >> 23) & 0xFF) - 127;
    var significand = (bytes & ~(-1 << 23));

    if (exponent == 128) 
        return sign * ((significand) ? Number.NaN : Number.POSITIVE_INFINITY);

    if (exponent == -127) {
        if (significand == 0) return sign * 0.0;
        exponent = -126;
        significand /= (1 << 22);
    } else significand = (significand | (1 << 23)) / (1 << 23);

    return sign * significand * Math.pow(2, exponent);
}

给定一个包含 4 个字节的整数,其中包含一个 IEEE-754 32 位单精度浮点数,这将生成(大致)正确的 Javascript 数字值,而无需使用任何循环。

@Haravikk,如何获取数字的位表示?
2021-03-15 09:29:23
@Pacerier:我对另一个问题的回答应该对此有所帮助:stackoverflow.com/a/16043259/2187548
2021-03-20 09:29:23
if (significand == 0) return sign * 0.0;- 零的倍数肯定是......零?是否-1 * 0.0产生负零?
2021-04-11 09:29:23

如果您需要一个功能强大的解决方案,Koolinc 的代码段是很好的,但如果您需要有限使用它,您最好编写自己的代码。我编写了以下函数,用于将字节的字符串十六进制表示形式转换为浮点数:

function decodeFloat(data) {
    var binary = parseInt(data, 16).toString(2);
    if (binary.length < 32) 
        binary = ('00000000000000000000000000000000'+binary).substr(binary.length);
    var sign = (binary.charAt(0) == '1')?-1:1;
    var exponent = parseInt(binary.substr(1, 8), 2) - 127;
    var significandBase = binary.substr(9);
    var significandBin = '1'+significandBase;
    var i = 0;
    var val = 1;
    var significand = 0;

    if (exponent == -127) {
        if (significandBase.indexOf('1') == -1)
            return 0;
        else {
            exponent = -126;
            significandBin = '0'+significandBase;
        }
    }

    while (i < significandBin.length) {
        significand += val * parseInt(significandBin.charAt(i));
        val = val / 2;
        i++;
    }

    return sign * significand * Math.pow(2, exponent);
}

维基百科上对所有格式的浮点进行双向转换的算法都有详细的解释,使用这些算法编写自己的代码很容易。从数字转换为字节应该更困难,因为您需要先对数字进行标准化。

我已经扩展了这个解决方案来处理 64 位浮点数和小端编码。它还需要一个字节数组而不是一个 base-16 字符串(这样 64 位浮点数就可以正常工作而不会出现舍入问题)。要点.github.com/2192799
2021-03-30 09:29:23

我有一个类似的问题,我想将任何 javascript 数字转换为一个缓冲区,然后将其解析回来而不对其进行字符串化。

function numberToBuffer(num) {
  const buf = new Buffer(8)
  buf.writeDoubleLE(num, 0)
  return buf
}

使用示例:

// convert a number to buffer
const buf = numberToBuffer(3.14)
// and then from a Buffer
buf.readDoubleLE(0) === 3.14

这适用于当前的 Node LTS (4.3.1) 及更高版本。低版本没测试。

在 Node.JS 10.15 上测试,此解决方案似乎比使用类型化数组更快。显然,如果您不使用 Node.JS,则不能使用缓冲区。
2021-04-08 09:29:23
我可以确认这也适用于 Node.js 0.10.40。使用旧版本的 Node-RED (0.11.1) 我显然无法访问 Float32Array 所以你的解决方案是我唯一的解决方案!我使用 'new Buffer(array)' 从 4 字节二进制浮点数组创建缓冲区,并使用 buffer.readFloatBE(0) 来检索浮点数。
2021-04-10 09:29:23

请问这段代码的帮助?

var parser = new BinaryParser
  ,forty = parser.encodeFloat(40.0,2,8) 
  ,twenty = parser.encodeFloat(20.0,2,8);  
console.log(parser.decodeFloat(forty,2,8).toFixed(1));   //=> 40.0
console.log(parser.decodeFloat(twenty,2,8).toFixed(1));  //=> 20.0
不要使用这个 BinaryParser 类!严格兼容(它使用with)!
2021-03-17 09:29:23
拥有 BinaryParser 使您依赖于该片段。
2021-03-28 09:29:23
该片段中使用的算法被彻底破坏。当用于读取浮点数或双精度数时,它在特定值上失败。例如,它将 40.0 读作 32.0,将 20.0 读作 16.0。
2021-04-06 09:29:23