web-dev-qa-db-ja.com

JavaScriptで整数をバイナリに変換する方法

正または負の整数を2進数で表示したいのですが。

この質問の に似ていますが、JavaScript用です。

247
barlop

この回答は、Number.MAX_SAFE_INTEGER(または2**53-1)と2**31の間の絶対値で整数をアドレス指定しようとします。現在のソリューションは32ビット以内の符号付き整数のみを扱いますが、このソリューションはfloat64ToInt64Binary()を使用して64ビットの2の補数形式で出力します。

// IIFE to scope internal variables
var float64ToInt64Binary = (function () {
  // create union
  var flt64 = new Float64Array(1)
  var uint16 = new Uint16Array(flt64.buffer)
  // 2**53-1
  var MAX_SAFE = 9007199254740991
  // 2**31
  var MAX_INT32 = 2147483648

  function uint16ToBinary() {
    var bin64 = ''

    // generate padded binary string a Word at a time
    for (var Word = 0; Word < 4; Word++) {
      bin64 = uint16[Word].toString(2).padStart(16, 0) + bin64
    }

    return bin64
  }

  return function float64ToInt64Binary(number) {
    // NaN would pass through Math.abs(number) > MAX_SAFE
    if (!(Math.abs(number) <= MAX_SAFE)) {
      throw new RangeError('Absolute value must be less than 2**53')
    }

    var sign = number < 0 ? 1 : 0

    // shortcut using other answer for sufficiently small range
    if (Math.abs(number) <= MAX_INT32) {
      return (number >>> 0).toString(2).padStart(64, sign)
    }

    // little endian byte ordering
    flt64[0] = number

    // subtract bias from exponent bits
    var exponent = ((uint16[3] & 0x7FF0) >> 4) - 1022

    // encode implicit leading bit of mantissa
    uint16[3] |= 0x10
    // clear exponent and sign bit
    uint16[3] &= 0x1F

    // check sign bit
    if (sign === 1) {
      // apply two's complement
      uint16[0] ^= 0xFFFF
      uint16[1] ^= 0xFFFF
      uint16[2] ^= 0xFFFF
      uint16[3] ^= 0xFFFF
      // propagate carry bit
      for (var Word = 0; Word < 3 && uint16[Word] === 0xFFFF; Word++) {
        // apply integer overflow
        uint16[Word] = 0
      }

      // complete increment
      uint16[Word]++
    }

    // only keep integer part of mantissa
    var bin64 = uint16ToBinary().substr(11, Math.max(exponent, 0))
    // sign-extend binary string
    return bin64.padStart(64, sign)
  }
})()

console.log('8')
console.log(float64ToInt64Binary(8))
console.log('-8')
console.log(float64ToInt64Binary(-8))
console.log('2**33-1')
console.log(float64ToInt64Binary(2**33-1))
console.log('-(2**33-1)')
console.log(float64ToInt64Binary(-(2**33-1)))
console.log('2**53-1')
console.log(float64ToInt64Binary(2**53-1))
console.log('-(2**53-1)')
console.log(float64ToInt64Binary(-(2**53-1)))
console.log('2**52')
console.log(float64ToInt64Binary(2**52))
console.log('-(2**52)')
console.log(float64ToInt64Binary(-(2**52)))
console.log('2**52+1')
console.log(float64ToInt64Binary(2**52+1))
console.log('-(2**52+1)')
console.log(float64ToInt64Binary(-(2**52+1)))
.as-console-wrapper {
  max-height: 100% !important;
}

この回答では、 IEEE-754倍精度浮動小数点形式 を重点的に扱います。

IEEE-754 Double-precision floating-point format

   seee eeee eeee ffff ffff ffff ffff ffff ffff ffff ffff ffff ffff ffff ffff ffff
   ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ----
   [    uint16[3]    ] [    uint16[2]    ] [    uint16[1]    ] [    uint16[0]    ]
   [                                   flt64[0]                                  ]

   little endian byte ordering

   s = sign = uint16[3] >> 15
   e = exponent = (uint16[3] & 0x7FF) >> 4
   f = fraction

このソリューションのしくみは、64ビット浮動小数点数と符号なし16ビット整数配列の間にリトルエンディアンのバイト順で結合することです。整数入力範囲を検証した後、入力をバッファ上の倍精度浮動小数点数にキャストしてから、共用体を使用して値へのビットアクセスを取得し、不偏バイナリ指数と小数ビットに基づいてバイナリ文字列を計算します。

このソリューションは純粋なECMAScript 5で実装されていますが、 String#padStart() を使用する点が異なります。これには ここで利用可能なpolyfillがあります

22
Patrick Roberts
function dec2bin(dec){
    return (dec >>> 0).toString(2);
}

dec2bin(1);    // 1
dec2bin(-1);   // 11111111111111111111111111111111
dec2bin(256);  // 100000000
dec2bin(-256); // 11111111111111111111111100000000

あなたは Number.toString(2) 関数を使うことができますが、負の数を表すときにはいくつか問題があります。たとえば、(-1).toString(2)の出力は"-1"です。

この問題を解決するには、符号なし右シフトビット演算子( >>> )を使用して、自分の数値を符号なし整数に変換します。

(-1 >>> 0).toString(2)を実行すると、あなたの数を0ビット右にシフトします。それは数自体を変えることはありませんが、それは符号なし整数として表されます。上記のコードは"11111111111111111111111111111111"を正しく出力します。

この質問 にはさらに説明があります。

-3 >>> 0(右論理シフト)は、引数を符号なし整数に強制変換します。これが、32ビットの2の補数表現である-3を取得する理由です。


注1:この回答は引数として数値を期待しているので、それに応じて変換します。

Note 2:結果は、の先頭になしの文字列なので、必要に応じてパディングを適用します。

412
fernandosavio

やってみる

num.toString(2);

2は基数で、2から36までの任意の基数にすることができます。

ソース はこちら

アップデート:

これは正数に対してのみ機能します。Javascriptは負の2進整数を2の補数表記で表します。私はトリックをするべきであるこの小さな機能を作った、私はそれをきちんとテストしていない:

function dec2Bin(dec)
{
    if(dec >= 0) {
        return dec.toString(2);
    }
    else {
        /* Here you could represent the number in 2s compliment but this is not what 
           JS uses as its not sure how many bits are in your number range. There are 
           some suggestions https://stackoverflow.com/questions/10936600/javascript-decimal-to-binary-64-bit 
        */
        return (~dec).toString(2);
    }
}

私は ここから助けを得ました

176
Manatok

「バイナリに変換」のバイナリは、主に3つのことを指すことができます。位置番号システム、メモリ内のバイナリ表現、または32ビットのビット文字列。 (64ビットのビット文字列については、 Patrick Robertsの回答 を参照)

1.ナンバーシステム

(123456).toString(2)は、数値を基数2 の定位置系 に変換します。このシステムでは、負数は10進数と同じようにマイナス記号で書かれます。

2.内部表現

数値の内部表現は 64ビット浮動小数点 であり、いくつかの制限がこの答えで説明されています。 簡単な方法はありません JavaScriptでこれのビット文字列表現を作成したり、特定のビットにアクセスすることはできません。

3.マスクとビット演算子

MDNはビットごとの演算子がどのように機能するかについて 概要 を示しています。重要なこと

ビット演算子は、それらのオペランドを 32ビット のシーケンス(0と1)として扱います。

演算が適用される前に、64ビットの浮動小数点数は32ビットの符号付き整数にキャストされます。彼らは戻って変換された後。

これは、数値を32ビット文字列に変換するためのMDNコード例です。

function createBinaryString (nMask) {
  // nMask must be between -2147483648 and 2147483647
  for (var nFlag = 0, nShifted = nMask, sMask = ""; nFlag < 32;
       nFlag++, sMask += String(nShifted >>> 31), nShifted <<= 1);
  return sMask;
}

createBinaryString(0) //-> "00000000000000000000000000000000"
createBinaryString(123) //-> "00000000000000000000000001111011"
createBinaryString(-1) //-> "11111111111111111111111111111111"
createBinaryString(-1123456) //-> "11111111111011101101101110000000"
createBinaryString(0x7fffffff) //-> "01111111111111111111111111111111"
45
Annan

簡単な方法はただ...

Number(42).toString(2);

// "101010"
37
ad rees

注意 - xが正である場合、基本的な(x>>>0).toString(2);はわずかな問題を抱えています。私は私の答えの最後に、まだ>>>を使用しながら>>>メソッドに関するその問題を修正するいくつかのサンプルコードを持っています。

(-3>>>0).toString(2);

prints -3 in 2s complement.

1111111111101

実用的な例

C:\>type n1.js
console.log(   (-3 >>> 0).toString(2)    );
C:\>
C:\>node n1.js
11111111111111111111111111111101

C:\>

URLバーのこれは別の簡単な証明です

javascript:alert((-3>>>0).toString(2))

注 - 結果は常に1から始まるという点で非常にわずかに欠陥があります。負の数の場合、これは問題ありません。正の数の場合は、結果が実際に2の補数になるように、先頭に0を追加する必要があります。そのため、(8>>>0).toString(2)は1000を生成しますが、実際には2の補数の8の倍数ではありませんが、その0の前に01000を付けると、2の補数の8の倍数になります。適切な2の補数では、0で始まるビット列は> = 0で、1で始まるビット列は負です。

例えばこれはその問題を回避します

// or x=-5  whatever number you want to view in binary  
x=5;   
if(x>0) prepend="0"; else prepend=""; 
alert(prepend+((x>>>0)).toString(2));

他の解決策はAnnanからのもの(Annanの説明と定義はエラーでいっぱいですが、彼は正しい出力を生成するコードを持っています)、そしてPatrickからの解決策です。

2の補数で0から始まる正の数および1から始まる負の数の事実を理解していない人は、2の補数でこのSO QnAをチェックできます。 「2の補数」とは何ですか?

9
barlop

あなたはビットの配列を返すあなた自身の関数を書くことができます。数値をビットに変換する方法の例

除数|配当|ビット/剰余

2 | 9 | 1

2 | 4 | 0

2 | 2 | 0

〜| 1 |〜

上記の行の例:2 * 4 = 8、剰余は1なので9 = 1 0 0 1

function numToBit(num){
    var number = num
    var result = []
    while(number >= 1 ){
        result.unshift(Math.floor(number%2))
        number = number/2
    }
    return result
}

残りを下から上に読みます。真ん中の1桁目を上にします。

6
supritshah1289

別のアプローチを使用して、これを行うものを思い付きました。私は自分のプロジェクトでこのコードを使用しないことにしましたが、誰かに役立つ場合に備えて、適切な場所に残しておくと思いました。

  • ビットシフトまたは2の補数強制を使用しません。
  • 出てくるビット数を選択します(有効な値「8」、「16」、「32」をチェックしますが、変更できると思います)
  • 符号付き整数として扱うか符号なし整数として扱うかを選択します。
  • エラー処理を改善したいが、符号付き/符号なしとビット数の組み合わせを与えられた範囲の問題をチェックします。
  • また、ビットをintに変換する「逆」バージョンの関数もあります。この出力を解釈するものはおそらく他にないので、これが必要になります:D
function intToBitString(input, size, unsigned) {
        if ([8, 16, 32].indexOf(size) == -1) {
                throw "invalid params";
        }
        var min = unsigned ? 0 : - (2 ** size / 2);
        var limit = unsigned ? 2 ** size : 2 ** size / 2;
        if (!Number.isInteger(input) || input < min || input >= limit) {
                throw "out of range or not an int";
        }
        if (!unsigned) {
                input += limit;
        }
        var binary = input.toString(2).replace(/^-/, '');
        return binary.padStart(size, '0');
}

function bitStringToInt(input, size, unsigned) {
        if ([8, 16, 32].indexOf(size) == -1) {
                throw "invalid params";
        }
        input = parseInt(input, 2);
        if (!unsigned) {
                input -= 2 ** size / 2;
        }
        return input;
}


// EXAMPLES

var res;
console.log("(uint8)10");
res = intToBitString(10, 8, true);
console.log("intToBitString(res, 8, true)");
console.log(res);
console.log("reverse:", bitStringToInt(res, 8, true));
console.log("---");

console.log("(uint8)127");
res = intToBitString(127, 8, true);
console.log("intToBitString(res, 8, true)");
console.log(res);
console.log("reverse:", bitStringToInt(res, 8, true));
console.log("---");

console.log("(int8)127");
res = intToBitString(127, 8, false);
console.log("intToBitString(res, 8, false)");
console.log(res);
console.log("reverse:", bitStringToInt(res, 8, false));
console.log("---");

console.log("(int8)-128");
res = intToBitString(-128, 8, false);
console.log("intToBitString(res, 8, true)");
console.log(res);
console.log("reverse:", bitStringToInt(res, 8, true));
console.log("---");

console.log("(uint16)5000");
res = intToBitString(5000, 16, true);
console.log("intToBitString(res, 16, true)");
console.log(res);
console.log("reverse:", bitStringToInt(res, 16, true));
console.log("---");

console.log("(uint32)5000");
res = intToBitString(5000, 32, true);
console.log("intToBitString(res, 32, true)");
console.log(res);
console.log("reverse:", bitStringToInt(res, 32, true));
console.log("---");
0
braks