Чтение / запись байтов с плавающей точкой в ​​JS - PullRequest
21 голосов
/ 11 декабря 2010

Можно ли как-то прочитать байты значения с плавающей запятой в JS? Что мне нужно, это записать необработанное значение FLOAT или DOUBLE в какой-то двоичный формат, который мне нужно сделать, поэтому есть ли способ получить побайтовое представление IEEE 754? И тот же вопрос для написания конечно.

Ответы [ 6 ]

38 голосов
/ 12 мая 2012

Вы можете сделать это с типизированными массивами :

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

Не уверен, какова поддержка браузера, хотя

7 голосов
/ 14 апреля 2013

Я создал расширение решения 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 байта, в которых хранится 32-разрядное число с плавающей запятой IEEE-754 с одинарной точностью, получится (приблизительно) правильное значение числа Javascript без использования циклов.

3 голосов
/ 02 марта 2016

У меня была похожая проблема, я хотел преобразовать любой номер 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

Это работает на текущем узле LTS (4.3.1) и выше. не тестировал в более низких версиях.

3 голосов
/ 17 декабря 2011

Фрагмент 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);
}

В википедии есть подробное объяснение алгоритмов, используемых для преобразования в обоих направлениях для всех форматов с плавающей запятой, и их легко использовать для написания собственного кода. Преобразование из числа в байты должно быть более трудным, потому что сначала вам нужно нормализовать число.

3 голосов
/ 11 декабря 2010

Может ли этот фрагмент помочь?

@ Кевин Гадд :

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
0 голосов
/ 11 декабря 2010

Полагаю, вы могли бы это понять, но я полагаю, вы спрашиваете, есть ли что-то встроенноеНе так далеко, как я когда-либо слышал;см. разделы 8.5 и 15.7 спецификации .

...