LoginSignup
0
0

More than 3 years have passed since last update.

JavaScriptで任意桁数の四則演算

Last updated at Posted at 2019-12-17

備忘録として。

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

追記(必読)

@nagtkk さんよりコメントで指摘をいただきました。

console.log(BigInt(12345678901234567890) + BigInt(12345678901234567890));

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

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

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

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

追記ここまで


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

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

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

加算

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)

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;
}
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

乗算

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

除算

まだ
0
0
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0