備忘録として。
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
##除算
まだ