web-dev-qa-db-ja.com

JavaScript:2つの2進数を追加する(2進数を返す)

バイナリで2つの入力があり、加算結果もバイナリで返しています。

var addBinary = function(a, b) {
    var dec = Number(parseInt(a, 2)) + Number(parseInt(b, 2));
    return dec.toString(2);
};

のようなめちゃくちゃ大きなバイナリの場合

a = 10100000100100110110010000010101111011011001101110111111111101000000101111001110001111100001101

b = 110101001011101110001111100110001010100001101011101010000011011011001011101111001100000011011110011

出力しています

110111101100010011000101110110100000011101000101011000000000000000000000000000000000000000000000000

想定される正しい出力は

110111101100010011000101110110100000011101000101011001000011011000001100011110011010010011000000000

オーバーフローのせいですか?もしそうなら、バイナリ追加のオーバーフローに対するJavaScriptの制限は何ですか? 1と0の束でごめんなさい。

9
patrickhuang94

Javascriptでバイナリを追加するためのソリューションを開発しました。

私の最初の目標は、Javascriptのデジタルバイナリ加算回路で使用されているメカニズムを複製することで、バイナリロジックの理解を深めることでした(ベース変換やビットごとの演算子は使用されていません)。

CodePen で私の元のプロジェクトの作業バージョンを見つけることができます。

DOMで必要以上に多くのことを行っていますが、(下記の調整を加えて)数値を差し込んだとき、それが機能することを嬉しく思いました!

Working Solution Code <<このプロジェクトは元のプロジェクトから変更され、正しい答えを出力するために必要なコードのみが含まれています。

このソリューションでは、abが同じ長さの文字列であると想定しています。このソリューションを使用するには、入力変数を次のように変更する必要があります。

_var a = "000010100000100100110110010000010101111011011001101110111111111101000000101111001110001111100001101"

var b = "110101001011101110001111100110001010100001101011101010000011011011001011101111001100000011011110011"
_

(私は_var a_の前の欠けている数字をゼロで埋めたところです。)

ご覧のとおり、バイナリ加算回路の物理的な実装で使用されるすべてのコンポーネントを再作成しました。

半加算器:

_function halfAdder(a, b){
  const sum = xor(a,b);
  const carry = and(a,b);
  return [sum, carry];
}
_

全加算:

_function fullAdder(a, b, carry){
  halfAdd = halfAdder(a,b);
  const sum = xor(carry, halfAdd[0]);
  carry = and(carry, halfAdd[0]);
  carry = or(carry, halfAdd[1]);
  return [sum, carry];
}
_

論理ゲート:

_function xor(a, b){return (a === b ? 0 : 1);}
function and(a, b){return a == 1 && b == 1 ? 1 : 0;}
function or(a, b){return (a || b);}
_

主な機能:

_function addBinary(a, b){

  let sum = '';
  let carry = '';

  for(var i = a.length-1;i>=0; i--){
    if(i == a.length-1){
      //half add the first pair
      const halfAdd1 = halfAdder(a[i],b[i]);
      sum = halfAdd1[0]+sum;
      carry = halfAdd1[1];
    }else{
      //full add the rest
      const fullAdd = fullAdder(a[i],b[i],carry);
      sum = fullAdd[0]+sum;
      carry = fullAdd[1];
    }
  }

  return carry ? carry + sum : sum;
}
_

したがって、addBinary(a,b)は正しい答えを生成します!

_var a = "000010100000100100110110010000010101111011011001101110111111111101000000101111001110001111100001101"
var b = "110101001011101110001111100110001010100001101011101010000011011011001011101111001100000011011110011"
var answer = "110111101100010011000101110110100000011101000101011001000011011000001100011110011010010011000000000";

console.log(addBinary(a, b) == answer); //true
_

ここで行ったことの一部があなたにも役立つことを願っています!

13

これは私の考えです:

小学校で教えられたように、右端の数字から始まるロジックは単純です。最初の数字の最後の数字と2番目の数字の最後の数字を追加し、次のラウンドのキャリーを保持します。

各ラウンド(while内)で、両方の数値を右トリミングします。たとえば、次のようにします。

// number
1101 -> 110
// The math is simple: 1101/10|0 (divide by 10 and convert to integer)

入力と出力はStringsで、 JS maximum integer の制限を克服します。この場合、文字列の長さがはるかに長くなる可能性があります。

完全なコード:

function binaryAddition(a,b){
  var result = "",
      carry = 0;

  while(a || b || carry){
    let sum = +a.slice(-1) + +b.slice(-1) + carry; // get last digit from each number and sum 

    if( sum > 1 ){  
      result = sum%2 + result;
      carry = 1;
    }
    else{
      result = sum + result;
      carry = 0;
    }
    
    // trim last digit (110 -> 11)
    a = a.slice(0, -1)
    b = b.slice(0, -1)
  }
  
  return result;
}

// Tests
[
  ["0","0"],
  ["1","1"],
  ["1","0"],
  ["0","1"],
  ["10","1"],
  ["11","1"],
  ["10","10"],
  ["111","111"],
  ["1010","11"]
].forEach(numbers => 
   document.write(
     numbers[0] + " + " + 
     numbers[1] + " = " + 
     binaryAddition(numbers[0], numbers[1]) + 
     "      <mark> (" +
     parseInt(numbers[0], 2) + " + " + 
     parseInt(numbers[1], 2) + " = " + 
     parseInt(binaryAddition(numbers[0], numbers[1]),2) +
     ")</mark><br>" 
   )
)
document.body.style="font:16px monospace";
5
vsync

異なる長さのバイナリ文字列をサポートする一般的なソリューション

Cassandra Wilcox'spadZeroes()関数を追加しました---素晴らしい answer さまざまな長さのバイナリ文字列をサポートする一般的なソリューションを作成します????

私はこのソリューションを 追加バイナリ問題leetcode に対してテストしたので、かなり堅牢なはずです。

/**
 * @param {string} a
 * @param {string} b
 * @return {string}
 */

// logic gates
function xor(a, b) {
  return a === b ? 0 : 1;
}

function and(a, b) {
  return a == 1 && b == 1 ? 1 : 0;
}

function or(a, b) {
  return a || b;
}

function halfAdder(a, b) {
  const sum = xor(a, b);
  const carry = and(a, b);
  return [sum, carry];
}

function fullAdder(a, b, carry) {
  halfAdd = halfAdder(a, b);
  const sum = xor(carry, halfAdd[0]);
  carry = and(carry, halfAdd[0]);
  carry = or(carry, halfAdd[1]);
  return [sum, carry];
}

function padZeroes(a, b) {
  const lengthDifference = a.length - b.length;
  switch (lengthDifference) {
    case 0:
      break;
    default:
      const zeroes = Array.from(Array(Math.abs(lengthDifference)), () =>
        String(0)
      );
      if (lengthDifference > 0) {
        // if a is longer than b
        // then we pad b with zeroes
        b = `${zeroes.join('')}${b}`;
      } else {
        // if b is longer than a
        // then we pad a with zeroes
        a = `${zeroes.join('')}${a}`;
      }
  }
  return [a, b];
}

function addBinary(a, b) {
  let sum = '';
  let carry = '';

  const paddedInput = padZeroes(a, b);
  a = paddedInput[0];
  b = paddedInput[1];

  for (let i = a.length - 1; i >= 0; i--) {
    if (i == a.length - 1) {
      // half add the first pair
      const halfAdd1 = halfAdder(a[i], b[i]);
      sum = halfAdd1[0] + sum;
      carry = halfAdd1[1];
    } else {
      // full add the rest
      const fullAdd = fullAdder(a[i], b[i], carry);
      sum = fullAdd[0] + sum;
      carry = fullAdd[1];
    }
  }
  return carry ? carry + sum : sum;
}
2
Micah Stubbs

Javascriptの操作の精度を忘れて、数学で1つのバイナリをプラスする方法を考えてください。

例えば、 11 + 10

まず、右から左に始めます。今、1 + 0 = 1その後、次へ進みます。 1 + 1 = 10 Javascriptを使用している場合、結果を取得する方法。

Modは残りの番号を取得でき、Divisionはキャリーを取得できることはわかっています。 10進法では、1 + 1 = 2、転送方法2から10。使用できます

result % 2   // we can get single digit
result / 2 | 0   // we can get tens digit, `| 0` can remove decimal.

これで、2つの文字列を連結することができます。

BinaryNumber = result / 2 | 0 + result % 2 + ''  // string concat

したがって、最終的なコードは次のようになります。

/**
 * @param {string} a
 * @param {string} b
 * @return {string}
 */
var addBinary = function(a, b) {
    var i = a.length - 1;
    var j = b.length - 1;
    var carry = 0;
    var result = "";
    while(i >= 0 || j >= 0) {
        var m = i < 0 ? 0 : a[i] | 0;
        var n = j < 0 ? 0 : b[j] | 0;
        carry += m + n; // sum of two digits
        result = carry % 2 + result; // string concat
        carry = carry / 2 | 0; // remove decimals,  1 / 2 = 0.5, only get 0
        i--;
        j--;
    }
    if(carry !== 0) {
        result = carry + result;
    }
    return result;
};
2
HectorGuo

私の意見では、これらの数値が大きすぎて精度を失うことができないためです。

var addBinary = function(a, b) {
    var dec = Number(parseInt(a, 2)) + Number(parseInt(b, 2));
    console.log("the number a is " + parseInt(a, 2));
    console.log("the number b is " + parseInt(b, 2));
    console.log("the dec is  " + dec);
    return dec.toString(2);
};
var a = "10100000100100110110010000010101111011011001101110111111111101000000101111001110001111100001101"
var b = "110101001011101110001111100110001010100001101011101010000011011011001011101111001100000011011110011"
console.log(addBinary(a, b));

結果は

the number a is 2.484789315402498e+28
the number b is 5.2670055459872975e+29
the dec is  5.515484477527547e+29
110111101100010011000101110110100000011101000101011000000000000000000000000000000000000000000000000

Numaとnumbの両方の損失精度を確認できます。最後の結果をバイナリに変換すると、次のようになります。

 parseInt("110111101100010011000101110110100000011101000101011000000000000000000000000000000000000000000000000", 2)

それからあなたは得る:

 5.515484477527547e+29. 

したがって、「toString(2)」のプロセスは正しいです。

この問題を解決するために手動でバイナリのプロセスをシミュレーションします(入力文字列が正しいため、コードで例外をキャッチしません。ランタイム環境はnodejs v4.6.0です)。

"use strict"
let addBinarybyChainhelen = function(a, b) {
    let alen = a.length;
    let blen = b.length;

    let i = alen - 1;
    let j = blen - 1;

    let result  = "";
    let carry   = 0;

    while(i >= 0 && j >= 0) {
        let acur = parseInt(a[i], 10);
        let bcur = parseInt(b[j], 10);

        let rcur = (acur + bcur + carry) % 2;
        carry = parseInt((acur + bcur + carry) / 2); 

        result += rcur;

        i--;
        j--;
    }

    while(i >= 0) {
        let acur = parseInt(a[i], 10);
        let rcur = (acur + carry) % 2;
        carry = parseInt((acur + carry) / 2); 

        result += rcur;
        i--;
    }

    while(j >= 0) {
        let bcur = parseInt(b[j], 10);
        let rcur = (bcur + carry) % 2;
        carry = parseInt((bcur + carry) / 2); 

        result += rcur;
        j--;
    }

    if(carry) {
        result += carry;
    }

    return result.split("").reverse().join("");
}


// use the function
let a = "10100000100100110110010000010101111011011001101110111111111101000000101111001110001111100001101" 
let b = "110101001011101110001111100110001010100001101011101010000011011011001011101111001100000011011110011"
console.log(addBinarybyChainhelen(a, b))

想定される正しい出力を取得する

110111101100010011000101110110100000011101000101011001000011011000001100011110011010010011000000000
1
chainhelen

これは、いくつかの条件ステートメントを使用した私の解決策です。

function addBinary(a, b) {
  let result = "";
  let i = a.length - 1;
  let j = b.length - 1;
  let carry = 0;

  while (i >= 0 || j >= 0 || carry > 0) {
    const x = parseInt(a[i], 10) || 0;
    const y = parseInt(b[j], 10) || 0;
    const z = x + y + carry;
    i--, j--;

    // error handling: non-binary number
    if (z > 3 || z < 0) return console.error("non-binary number");

    result = z === 3 || z === 1 ? 1 + result : 0 + result;
    carry = z < 2 ? 0 : 1;
  }

  return result;
}

条件ステートメントのロジックは、次のスイッチ/ケースを使用する場合と同じです。

switch (z) {
   case 3:
      result = 1 + result;
      carry = 1;
      continue;
   case 2:
      result = 0 + result;
      carry = 1;
      continue;
   case 1:
      result = 1 + result;
      carry = 0;
      continue;
   case 0:
      result = 0 + result;
      carry = 0;
      continue;
   default:
      return console.error("non-binary number");
}
0
Darcy

私のソリューションも追加したい

let a = '1111';
let b = '1111';
let addBinary = (a, b) => {

  let highestNumber;
  let lowestNumber;
  let answer = '';
  let carry = 0;

        let aArr = a.split('');
  let bArr = b.split('');
  
  if(aArr.length > bArr.length) {
  
        highestNumber = aArr;
    lowestNumber = bArr;
  } else {
  
        highestNumber = bArr;
    lowestNumber = aArr;
  }
  
  let diff = highestNumber.length - lowestNumber.length;
  let startingInd = highestNumber.length - diff;
  
  
  for(let i= startingInd; i < highestNumber.length; i++) {
  
        lowestNumber = ['0'].concat(lowestNumber);
    
  }
  
  
  for(let i=highestNumber.length-1; i >= 0; i--) {
    
    let num1 = parseInt(highestNumber[i]);
    let num2 = parseInt(lowestNumber[i]);
    let sum = num1 + num2 + carry;
    
    let currValue = sum === 1 || sum === 3 ? '1' : '0';
    
    answer = currValue.concat(answer);
    
    
    if(sum === 3 || sum === 2) carry = 1;
    
  }
  
  if(carry == 1) answer = '1'.concat(answer);
  if(carry == 2) answer = '10'.concat(answer);
  
  return answer;
  
};


console.log(addBinary(a, b));
0
Senal

これは私の試みです...派手な単純なロジックはありません。

var addBinary = function(a, b) {
  let aLast = a.length - 1;
  let bLast = b.length - 1;

  let carry = 0;
  let aStr = [];

  while(aLast>=0 || bLast>=0){
    let sum = carry;
    if(aLast >= 0) {
      sum+= Number(a[aLast]);
      aLast--;
    }

    if(bLast >= 0) {
      sum+= Number(b[bLast]);
      bLast--
    }
    aStr.Push(sum%2);
    carry = Math.floor(sum/2);
  }

  if(carry)     aStr.Push(carry);

  return aStr.reverse().join("");
};
0
ShankyDoodle

ES6で最も短いバージョンのバリエーションを提案したいと思います(主な要件は、「この大きな問題を解決するために組み込みの大きな整数を使用しないこと」でした)。

// It's my challenge solution with 104 chars only:
addBinaryStrings = ([...a], [...b]) => {
    c = 0
    r = ''
    while (a[0] | b[0] | c) {
        c += ~~a.pop() + ~~b.pop()
        r = c%2 + r
        c = c > 1
    }
    return r
}

// Test:
binaryString1 = "1010110000000001101011001000010110101111110010100011011100101010000101011010001110011001011110111"
binaryString2 = "10100110100001100010010001111100001110100110111001100001011010011000101111001110100011101110000100100010001100110000001010011000100110"

string1.innerText = binaryString1;
string2.innerText = binaryString2;
expected.innerText = "10100110100001100010010001111100001111111100111001101110110011011011100101001100111000001001101001110010111000000001111101100100011101"
result.innerText = addBinaryStrings(binaryString1, binaryString2)
* {
  font-family: monospace;
}

div b {
  color: red;
}
div span {
  color: dodgerblue;
}
<div>BINARY&nbsp;1:&nbsp;<b id="string1"></b></div>
<div>SUMM&nbsp;&nbsp;&nbsp;&nbsp;:&nbsp;<span>+</span></div>
<div>BINARY&nbsp;2:&nbsp;<b id="string2"></b></div>
<div>FINALLY&nbsp;:&nbsp;<span>=</span></div>
<div>EXPECTED:&nbsp;<span id="expected"></span></div>
<div>RESULT&nbsp;&nbsp;:&nbsp;<span id="result"></span></div>
0