簡體   English   中英

如何在Javascript中將浮點數轉換為二進制表示(IEEE 754)?

[英]How to convert a floating point number to its binary representation (IEEE 754) in Javascript?

在Javascript中將浮點數轉換為二進制表示形式的最簡單方法是什么? (例如1.0 - > 0x3F800000)。

我試圖手動完成,這在一定程度上(通常的數字)起作用,但是對於非常大或非常小的數字(沒有范圍檢查)和特殊情況(NaN,無窮大等)都會失敗:

function floatToNumber(flt)
{
    var sign = (flt < 0) ? 1 : 0;
    flt = Math.abs(flt);
    var exponent = Math.floor(Math.log(flt) / Math.LN2);
    var mantissa = flt / Math.pow(2, exponent);

    return (sign << 31) | ((exponent + 127) << 23) | ((mantissa * Math.pow(2, 23)) & 0x7FFFFF);
}

我重新發明輪子了嗎?

編輯:我改進了我的版本,現在它處理特殊情況。

function assembleFloat(sign, exponent, mantissa)
{
    return (sign << 31) | (exponent << 23) | (mantissa);
}

function floatToNumber(flt)
{
    if (isNaN(flt)) // Special case: NaN
        return assembleFloat(0, 0xFF, 0x1337); // Mantissa is nonzero for NaN

    var sign = (flt < 0) ? 1 : 0;
    flt = Math.abs(flt);
    if (flt == 0.0) // Special case: +-0
        return assembleFloat(sign, 0, 0);

    var exponent = Math.floor(Math.log(flt) / Math.LN2);
    if (exponent > 127 || exponent < -126) // Special case: +-Infinity (and huge numbers)
        return assembleFloat(sign, 0xFF, 0); // Mantissa is zero for +-Infinity

    var mantissa = flt / Math.pow(2, exponent);
    return assembleFloat(sign, exponent + 127, (mantissa * Math.pow(2, 23)) & 0x7FFFFF);
}

我仍然不確定這是否100%正確,但似乎工作得足夠好。 (我仍然在尋找現有的實現)。

新技術使這很容易,也可能更加向前兼容。 我喜歡擴展內置原型,而不是每個人都這樣做。 所以隨意修改以下代碼到經典的程序方法:

(function() {
    function NumberToArrayBuffer() {
        // Create 1 entry long Float64 array
        return [new Float64Array([this]).buffer];
    }
    function NumberFromArrayBuffer(buffer) {
        // Off course, the buffer must be at least 8 bytes long, otherwise this is a parse error
        return new Float64Array(buffer, 0, 1)[0];
    }
    if(Number.prototype.toArrayBuffer)  {
        console.warn("Overriding existing Number.prototype.toArrayBuffer - this can mean framework conflict, new WEB API conflict or double inclusion.");
    }
    Number.prototype.toArrayBuffer = NumberToArrayBuffer;
    Number.prototype.fromArrayBuffer = NumberFromArrayBuffer;
    // Hide this methods from for-in loops
    Object.defineProperty(Number.prototype, "toArrayBuffer", {enumerable: false});
    Object.defineProperty(Number.prototype, "fromArrayBuffer", {enumerable: false});
})();

測試:

 (function() { function NumberToArrayBuffer() { // Create 1 entry long Float64 array return new Float64Array([this.valueOf()]).buffer; } function NumberFromArrayBuffer(buffer) { // Off course, the buffer must be ar least 8 bytes long, otherwise this is a parse error return new Float64Array(buffer, 0, 1)[0]; } if(Number.prototype.toArrayBuffer) { console.warn("Overriding existing Number.prototype.toArrayBuffer - this can mean framework conflict, new WEB API conflict or double inclusion."); } Number.prototype.toArrayBuffer = NumberToArrayBuffer; Number.fromArrayBuffer = NumberFromArrayBuffer; // Hide this methods from for-in loops Object.defineProperty(Number.prototype, "toArrayBuffer", {enumerable: false}); Object.defineProperty(Number, "fromArrayBuffer", {enumerable: false}); })(); var test_numbers = [0.00000001, 666666666666, NaN, Infinity, -Infinity,0,-0]; console.log("Conversion symethry test: "); test_numbers.forEach( function(num) { console.log(" ", Number.fromArrayBuffer((num).toArrayBuffer())); } ); console.log("Individual bytes of a Number: ",new Uint8Array((666).toArrayBuffer(),0,8)); 
 <script src="https://getfirebug.com/firebug-lite-debug.js"></script> 

這是一個適用於我測試過的所有內容的函數,除了它不區分-0.0和+0.0。

它基於來自http://jsfromhell.com/classes/binary-parser的代碼,但它專門用於32位浮點數並返回整數而不是字符串。 我也對它進行了修改,使其更快,(略微)更具可讀性。

// Based on code from Jonas Raoni Soares Silva
// http://jsfromhell.com/classes/binary-parser
function encodeFloat(number) {
    var n = +number,
        status = (n !== n) || n == -Infinity || n == +Infinity ? n : 0,
        exp = 0,
        len = 281, // 2 * 127 + 1 + 23 + 3,
        bin = new Array(len),
        signal = (n = status !== 0 ? 0 : n) < 0,
        n = Math.abs(n),
        intPart = Math.floor(n),
        floatPart = n - intPart,
        i, lastBit, rounded, j, exponent;

    if (status !== 0) {
        if (n !== n) {
            return 0x7fc00000;
        }
        if (n === Infinity) {
            return 0x7f800000;
        }
        if (n === -Infinity) {
            return 0xff800000
        }
    }

    i = len;
    while (i) {
        bin[--i] = 0;
    }

    i = 129;
    while (intPart && i) {
        bin[--i] = intPart % 2;
        intPart = Math.floor(intPart / 2);
    }

    i = 128;
    while (floatPart > 0 && i) {
        (bin[++i] = ((floatPart *= 2) >= 1) - 0) && --floatPart;
    }

    i = -1;
    while (++i < len && !bin[i]);

    if (bin[(lastBit = 22 + (i = (exp = 128 - i) >= -126 && exp <= 127 ? i + 1 : 128 - (exp = -127))) + 1]) {
        if (!(rounded = bin[lastBit])) {
            j = lastBit + 2;
            while (!rounded && j < len) {
                rounded = bin[j++];
            }
        }

        j = lastBit + 1;
        while (rounded && --j >= 0) {
            (bin[j] = !bin[j] - 0) && (rounded = 0);
        }
    }
    i = i - 2 < 0 ? -1 : i - 3;
    while(++i < len && !bin[i]);
    (exp = 128 - i) >= -126 && exp <= 127 ? ++i : exp < -126 && (i = 255, exp = -127);
    (intPart || status !== 0) && (exp = 128, i = 129, status == -Infinity ? signal = 1 : (status !== status) && (bin[i] = 1));

    n = Math.abs(exp + 127);
    exponent = 0;
    j = 0;
    while (j < 8) {
        exponent += (n % 2) << j;
        n >>= 1;
        j++;
    }

    var mantissa = 0;
    n = i + 23;
    for (; i < n; i++) {
        mantissa = (mantissa << 1) + bin[i];
    }
    return ((signal ? 0x80000000 : 0) + (exponent << 23) + mantissa) | 0;
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM