在javascript中双倍到字节数组转换

时间:2014-09-19 21:19:26

标签: javascript binary double

我正在尝试将一些Java代码转换为我正在处理的应用程序所需的JavaScript。我被困在一个类及其方法,将double类型的变量转换为long,然后长到一个字节数组,由8个字节组成,表示该长数字。 Java代码如下:

 public static byte[] doubleToByteArray(double number)
   {
     // double to long representation
     long longNum = Double.doubleToLongBits(number);

     // long to 8 bytes
     return new byte[] {(byte)((longNum >>> 56) & 0xFF),
                     (byte)((longNum >>> 48) & 0xFF),
                     (byte)((longNum >>> 40) & 0xFF),
                     (byte)((longNum >>> 32) & 0xFF),
                     (byte)((longNum >>> 24) & 0xFF),
                     (byte)((longNum >>> 16) & 0xFF),
                     (byte)((longNum >>>  8) & 0xFF),
                     (byte)((longNum >>>  0) & 0xFF)};
  }  // end doubleToByte(.)

我将如何在JavaScript中执行此操作?我的第一个问题是使用doubleToLongBits方法。 JavaScript中是否存在类似的内容?此外,如何将变量转换为字节?

提前谢谢你。

3 个答案:

答案 0 :(得分:1)

基于Brian's answerdesired representation,您可以按如下方式使用类型化数组:



function doubleToByteArray(number) {
    var buffer = new ArrayBuffer(8);         // JS numbers are 8 bytes long, or 64 bits
    var longNum = new Float64Array(buffer);  // so equivalent to Float64

    longNum[0] = number;

    return Array.from(new Int8Array(buffer)).reverse();  // reverse to get little endian
}

function interactiveExample() {
    var input = parseFloat(document.getElementById('input').value);
    var output = document.getElementById('output');
    var result = doubleToByteArray(input);

    output.innerHTML = '[' + result[0];
    for (var i = 1; i < result.length; i++) {
        output.innerHTML += ', ' + result[i];
    }
    output.innerHTML += ']';
}

document.getElementById('input').value = Math.PI;
interactiveExample();
&#13;
<input type="number" id="input" step="0.01" onchange="interactiveExample()" />
<div id="output"></div>
&#13;
&#13;
&#13;

答案 1 :(得分:0)

您可以使用类型化数组和ArrayBuffer来完成此任务。我不是浮点表示的专家,但这应该做你需要的:

function doubleToByteArray(number) {
    var buffer = new ArrayBuffer(4);
    var intView = new Int32Array(buffer);
    var floatView = new Float32Array(buffer);

    floatView[0] = number;

    // Debug: display binary representation of `number`
    // console.log(intView[0].toString(2));
    return [
        (intView[0] >> 24) & 0xFF,
        (intView[0] >> 16) & 0xFF,
        (intView[0] >>  8) & 0xFF,
        (intView[0] >>  0) & 0xFF,
        (intView[1] >> 24) & 0xFF,
        (intView[1] >> 16) & 0xFF,
        (intView[1] >>  8) & 0xFF,
        (intView[1] >>  0) & 0xFF
    ];
}

function interactiveExample() {
    var input = parseFloat(document.getElementById('input').value);
    var output = document.getElementById('output');
    var result = doubleToByteArray(input);

    output.innerHTML = '[' + result[0];
    for (var i = 1; i < result.length; i++) {
        output.innerHTML += ', ' + result[i];
    }
    output.innerHTML += ']';
}

document.getElementById('input').value = Math.PI;
interactiveExample();
<input type="number" id="input" step="0.01" onchange="interactiveExample()" />
<div id="output"></div>

答案 2 :(得分:0)

您可以查看JavaScript Exact Arithmetic。该网站实现了IEEE Double到ByteArray和ByteArray到IEEE Double的转换。 IEEE Double是Java使用的表示形式。因此,此站点生成的字节数组将使用Java转换为精确的double。

我已经提取了底层代码并构建了JRS库(对于J R Stockton,原始代码的作者)。 JRS库提供了两种方法:

  • doubleToHexString():将IEEE Double转换为十六进制字符串
  • hexStringToDouble():将十六进制字符串转换为IEEE Double

图书馆如下。请查看Copyright页面以了解合理使用情况。

JRS库如下:

/**
 * A library that allow conversion of double to byteArray and vis versa.
 * Extracted from "JRS - JavaScript Exact Arithmetic - J R Stockton (See
 * http://www.merlyn.demon.co.uk/js-exact.htm#DW4 and 
 * http://www.merlyn.demon.co.uk/contents.htm#Copy).
 */

JRS = function(){
    function numberToBinString(number, binStringLength) {
        var A = [], T = null; // number>=0
        while (binStringLength--) {
            T = number % 2;
            A[binStringLength] = T;
            number -= T;
            number /= 2;
        }
        return A.join("");
    }

    function HexFn(fourBitsBinString) {
        return parseInt(fourBitsBinString, 2).toString(16);
    }

    function binStringToHexString(binString) {
        return binString.replace(/(\d{4})/g, HexFn );
    }

    function hexStringToBinString(hexString) {
        var binString = "";

        for(var i=0; i< hexString.length-1; i+=2) {
            binString += numberToBinString(parseInt(hexString.substr(i, 2), 16), 8);
        }

        return binString;    
    }

    function SngFwd(Sg, Ex, Mt) {
        var B = {};
        Mt = Math.pow(2, 23) * Mt + 0.5; // round
        B.a = 0xFF & Mt;
        B.b = 0xFF & (Mt >> 8);
        B.c = 0x7F & (Mt >> 16) | (Ex & 1) << 7;
        B.d = Sg << 7 | (Ex >> 1);
        return B;
    }

    function DblFwd(Sg, Ex, Mt) {
        var B = {};
        Mt = Math.pow(2, 52) * Mt;
        B.a = 0xFFFF & Mt;
        B.b = 0xFFFF & (Mt >> 16);
        Mt /= Math.pow(2, 32); // Integers are only 32-bit
        B.c = 0xFFFF & Mt;
        B.d = Sg << 15 | Ex << 4 | 0x000F & (Mt >> 16);
        return B;
    }

    function CVTFWD(NumW, Qty) { // Function now without side-effects
        var Sign = null, Expo = null, Mant = null, Bin = null, nb01 = ""; // , OutW = NumW/4
        var Inf = {
            32 : {d: 0x7F, c: 0x80, b: 0, a : 0},
            64 : {d: 0x7FF0, c: 0, b: 0, a : 0}
        };
        var ExW = {32: 8, 64: 11}[NumW], MtW = NumW - ExW - 1;

        if (isNaN(Qty)) {
            Bin = Inf[NumW];
            Bin.a = 1;
            Sign = false;
            Expo = Math.pow(2, ExW) - 1;
            Mant = Math.pow(2, -MtW);
        }

        if (!Bin) {
            Sign = Qty < 0 || 1 / Qty < 0; // OK for +-0
            if (!isFinite(Qty)) {
                Bin = Inf[NumW];
                if (Sign)
                    Bin.d += 1 << (NumW / 4 - 1);
                Expo = Math.pow(2, ExW) - 1;
                Mant = 0;
            }
        }

        if (!Bin) {
            Expo = {32: 127, 64: 1023}[NumW];
            Mant = Math.abs(Qty);
            while (Mant >= 2) {
                Expo++;
                Mant /= 2;
            }
            while (Mant < 1 && Expo > 0) {
                Expo--;
                Mant *= 2;
            }
            if (Expo <= 0) {
                Mant /= 2;
                nb01 = "Zero or Denormal";
            }
            if (NumW == 32 && Expo > 254) {
                nb01 = "Too big for Single";
                Bin = {
                    d : Sign ? 0xFF : 0x7F,
                    c : 0x80,
                    b : 0,
                    a : 0
                };
                Expo = Math.pow(2, ExW) - 1;
                Mant = 0;
            }
        }

        if (!Bin)
            Bin = {32: SngFwd, 64: DblFwd}[NumW](Sign, Expo, Mant);

        Bin.sgn = +Sign;
        Bin.exp = numberToBinString(Expo, ExW);
        Mant = (Mant % 1) * Math.pow(2, MtW);
        if (NumW == 32)
            Mant = Math.floor(Mant + 0.5);
        Bin.mnt = numberToBinString(Mant, MtW);
        Bin.nb01 = nb01;
        return Bin;
    }

    function CVTREV(BinStr) {
        var ExW = {32: 8,64: 11}[BinStr.length];
        var M = BinStr.match(new RegExp("^(.)(.{" + ExW + "})(.*)$"));
        // M1 sign, M2 exponent, M3 mantissa

        var Sign = M[1] == "1" ? -1 : +1;

        if (!/0/.test(M[2])) { // NaN or Inf
            var X = /1/.test(M[3]) ? NaN : Sign / 0;
            throw new Error("Max Coded " + M[3] + " " + X.toString());
        }

        var Denorm = +M[2] == 0;
        if (Denorm) {
            console.log("Zero or Denormal");
        }

        var Expo = parseInt(M[2], 2) - Math.pow(2, ExW - 1) + 1;
        var Mant = parseInt(M[3], 2) / Math.pow(2, M[3].length) + !Denorm;
        return Sign * Mant * Math.pow(2, Expo + Denorm);
    }

    this.doubleToHexString = function( /* double */d, /* int */size) {
        var NumW = size;
        var Qty = d;
        with (CVTFWD(NumW, Qty)) {
            return binStringToHexString(sgn + exp + mnt);
        }
    };

    this.hexStringToDouble = function (/*String*/hexString, /*int*/size) {
        var NumW = size ;
        var binString = hexStringToBinString(hexString) ;
        var X = new RegExp("^[01]{" + NumW + "}$");
        if (!X.test(binString)) {
            alert(NumW + " bits 0/1 needed");
            return;
        }
        return CVTREV(binString);
    };
};