JavaScriptで任意桁数の四則演算

備忘録として。

JavaScriptにはBigIntとかってのがあるけど、BigIntも上限は流石にあるし、~~正確じゃない。~~使えない環境もある。

##追記(必読)
@nagtkk さんよりコメントで指摘をいただきました。

```javascript
console.log(BigInt(12345678901234567890) + BigInt(12345678901234567890));
```
この結果が不正確になるのは、そもそも数値型を渡そうとしているため、BigIntに渡った時点ですでに誤差が発生しているからです。

同じ様に、BigIntに数値を文字列として渡す事でBigIntでも上記計算は上手くいきます。

```javascript
console.log(BigInt("12345678901234567890") + BigInt("12345678901234567890"));
//[output] : 24691357802469135780n
```

**間違った情報を載せてしまった事をお詫び申し上げます。**
なお、初版の内容も併せて記載したままにしてあります。

追記ここまで

---


```javascript
// ----- 以下は数値を文字列で渡す事で回避可能。
console.log(BigInt(12345678901234567890) + BigInt(12345678901234567890));
//[output] : 24691357802469134336n
//正しい結果は  24691357802469135780
```

じゃあ文字列として扱って、自分が筆算やる時の過程をプログラムにすれば良いよねって事で任意精度の四則演算を実装してみた。

引数は全て文字列として受け取る前提。

##加算

```javascript
function add(a, b) {
    let a_rev = a.split("").reverse();
    let b_rev = b.split("").reverse();
    
    let loop = (a.length < b.length)? b.length: a.length;
    let carry = 0;
    let stack = [];
    for(var li = 0; li < loop; li++) {
        let add = (+a_rev[li] || 0) + (+b_rev[li] || 0) + carry;
        let num = add % 10;
        carry = (add >= 10)? 1: 0;
        stack[li] = num;
    }
    if(carry === 1) stack[li + 1] = carry;
    return stack.reverse().join("");
}

console.log(add("12345678901234567890", "12345678901234567890"));
//[output] : 24691357802469135780
```

##減算

大きい値と小さい値の比較があるのでまずはless thanの定義
### 小なり(a<b)
```javascript
function lessThan(a, b) {
    if(a.length < b.length) return true;
    if(a.length > b.length) return false;

    let a_arr = a.split("");
    let b_arr = b.split("");
    
    for(let li = 0; li < a_arr.length; li++) {
        if(+a_arr[li] < +b_arr[li]) return true;
        else if(+a_arr[li] > +b_arr[li]) return false;
        else continue;
    }
    return false;
}
```

```javascript
function sub(a, b) {
   let bigger, smaller;
   let flag = "";
    if(lessThan(a, b)) {
        flag = "-";
        bigger = b;
        smaller = a;
    } else {
        bigger = a;
        smaller = b;
    }
    
    let left = bigger.split("").reverse();
    let right = smaller.split("").reverse();
    
    let stack = [];
    for(let ri = 0; ri < right.length; ri++) {
        if(+left[ri] < right[ri]) {
            left[ri] = (+left[ri] + 10);
            for(let li = ri + 1; li < left.length; li++) {
                if(left[li] !== "0") {
                    left[li] = +left[li] - 1;
                    break;
                } else {
                    left[li] = "9";
                }
            }
        }
        let num = +left[ri] - right[ri];
        stack[ri] = num;
    }
    stack = stack.concat(left.slice(right.length));
    return flag + (stack.reverse().join("").replace(/^(0(?!$))+/, ""));
}

console.log(sub("12345678901234567890", "12345678901234567890"));
//[output] : 0
console.log(sub("12345678901234567890", "12345678901234567899"));
//[output] : -9
console.log(sub("12345678901234567899", "12345678901234567890"));
//[output] : 9
```

##乗算

```javascript
function mul(a, b) {
  let a_rev = a.split("").reverse();
  let b_rev = b.split("").reverse();
  
  let stack = [];
  for(let ai = 0; ai < a_rev.length; ai++) {
    for(let bi = 0; bi < b_rev.length; bi++) {
      let current = ai + bi;
      let mult = +a_rev[ai] * +b_rev[bi];
      stack[current] = (stack[current]) 
        ? stack[current] + mult
        : mult;
    }
  }
  
  for(let si = 0; si < stack.length; si++) {
    let num = stack[si] % 10;
    let carry = Math.floor(stack[si] / 10);
    stack[si] = num;
    
    if(stack[si + 1]) {
      stack[si + 1] += carry;
    } else if(carry > 0) {
      stack[si + 1] = carry;
    }
  }
  
  return stack.reverse().join("").replace(/^(0(?!$))+/, "");
}

console.log(mul("12345678901234567890", "12345678901234567890"));
//[output] : 152415787532388367501905199875019052100
```

##除算

```
まだ
```