在 JS 中读/写 float 字节

发布于 2024-10-07 12:49:48 字数 110 浏览 1 评论 0原文

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

Is there any way I can read bytes of a float value in JS? What I need is to write a raw FLOAT or DOUBLE value into some binary format I need to make, so is there any way to get a byte-by-byte IEEE 754 representation? And same question for writing of course.

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

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

发布评论

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

评论(6

仙气飘飘 2024-10-14 12:49:48

您可以使用类型化数组来实现:

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

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

You can do it with typed arrays:

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

Or another way:

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

Not sure what browser support is like though

梦行七里 2024-10-14 12:49:48

我创建了 Miloš 解决方案 的扩展,假设 TypedArray 不是当然是一个选项(在我的例子中,我正在使用它们不可用的环境):

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不使用任何循环的数值。

I've created an expansion of Miloš's solution that should be a bit faster, assuming TypedArrays are not an option of course (in my case I'm working with an environment where they're not available):

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

Given an integer containing 4 bytes holding an IEEE-754 32-bit single precision float, this will produce the (roughly) correct JavaScript number value without using any loops.

云归处 2024-10-14 12:49:48

如果您需要一个功能强大的解决方案,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);
}

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

Koolinc's snippet is good if you need a solution that powerful, but if you need it for limited use you are better off writing your own code. I wrote the following function for converting a string hex representation of bytes to a float:

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

There are detailed explanations of algorithms used to convert in both directions for all formats of floating points on wikipedia, and it is easy to use those to write your own code. Converting from a number to bytes should be more difficult because you need to normalize the number first.

逆夏时光 2024-10-14 12:49:48

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

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) 及更高版本。低版本没有测试。

I had a similar problem, I wanted to convert any javascript number to a Buffer and then parse it back without stringifying it.

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

Use example:

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

This works on current Node LTS (4.3.1) and up. didn't test in lower versions.

尤怨 2024-10-14 12:49:48

此代码段有帮助吗?

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

Would this snippet help?

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
聽兲甴掵 2024-10-14 12:49:48

64 位 IEEE 754 浮点到其二进制表示形式并返回:

// float64ToOctets(123.456) -> [64, 94, 221, 47, 26, 159, 190, 119]
function float64ToOctets(number) {
    const buffer = new ArrayBuffer(8);
    new DataView(buffer).setFloat64(0, number, false);
    return [].slice.call(new Uint8Array(buffer));
}

// octetsToFloat64([64, 94, 221, 47, 26, 159, 190, 119]) -> 123.456
function octetsToFloat64(octets) {
    const buffer = new ArrayBuffer(8);
    new Uint8Array(buffer).set(octets);
    return new DataView(buffer).getFloat64(0, false);
}

// intToBinaryString(8) -> "00001000"
function intToBinaryString(i, length) {
    return i.toString(2).padStart(8, "0");
}

// binaryStringToInt("00001000") -> 8
function binaryStringToInt(b) {
    return parseInt(b, 2);
}

function octetsToBinaryString(octets) {
    return octets.map((i) => intToBinaryString(i)).join("");
}

function float64ToBinaryString(number) {
    return octetsToBinaryString(float64ToOctets(number));
}

function binaryStringToFloat64(string) {
    return octetsToFloat64(string.match(/.{8}/g).map(binaryStringToInt));
}

console.log(float64ToBinaryString(123.123))
console.log(binaryStringToFloat64(float64ToBinaryString(123.123)))
console.log(binaryStringToFloat64(float64ToBinaryString(123.123)) === 123.123)

这是此 MIT 许可代码的稍微修改版本:https://github.com/bartaz/ieee754-visualization/blob/master/src/ieee754.js

64-bit IEEE 754 float to its binary representation and back:

// float64ToOctets(123.456) -> [64, 94, 221, 47, 26, 159, 190, 119]
function float64ToOctets(number) {
    const buffer = new ArrayBuffer(8);
    new DataView(buffer).setFloat64(0, number, false);
    return [].slice.call(new Uint8Array(buffer));
}

// octetsToFloat64([64, 94, 221, 47, 26, 159, 190, 119]) -> 123.456
function octetsToFloat64(octets) {
    const buffer = new ArrayBuffer(8);
    new Uint8Array(buffer).set(octets);
    return new DataView(buffer).getFloat64(0, false);
}

// intToBinaryString(8) -> "00001000"
function intToBinaryString(i, length) {
    return i.toString(2).padStart(8, "0");
}

// binaryStringToInt("00001000") -> 8
function binaryStringToInt(b) {
    return parseInt(b, 2);
}

function octetsToBinaryString(octets) {
    return octets.map((i) => intToBinaryString(i)).join("");
}

function float64ToBinaryString(number) {
    return octetsToBinaryString(float64ToOctets(number));
}

function binaryStringToFloat64(string) {
    return octetsToFloat64(string.match(/.{8}/g).map(binaryStringToInt));
}

console.log(float64ToBinaryString(123.123))
console.log(binaryStringToFloat64(float64ToBinaryString(123.123)))
console.log(binaryStringToFloat64(float64ToBinaryString(123.123)) === 123.123)

This is a slightly modified version this MIT-licensed code: https://github.com/bartaz/ieee754-visualization/blob/master/src/ieee754.js

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