次のスクリプトで q == 0 になっているのはなぜですか?
<script>
var start = 1234567890123456789;
var end = 1234567890123456799;
var q = end - start;
alert(q);
</script>
結果は 10 になると思います。これら 2 つの数値を減算する正しい方法は何ですか?
次のスクリプトで q == 0 になっているのはなぜですか?
<script>
var start = 1234567890123456789;
var end = 1234567890123456799;
var q = end - start;
alert(q);
</script>
結果は 10 になると思います。これら 2 つの数値を減算する正しい方法は何ですか?
JavaScript の数値は浮動小数点であるためです。精度は限られています。
JavaScript が非常に長い数値を検出すると、64 ビット浮動小数点として表現できる最も近い数値に丸めます。スクリプトでは、同じ値start
にend
丸められます。
alert(1234567890123456789); // says: 1234567890123456800
alert(1234567890123456799); // says: 1234567890123456800
大きな整数に対して正確な算術演算を行う組み込みの方法はありませんが、このような BigInteger ライブラリを使用できます。
ジェイソンはすでに理由を投稿しました。解決策として、 http: //www-cs-students.stanford.edu/~tjw/jsbn/ で Javascript BigInt ライブラリを入手できます。
const subtract = (a, b) => [a, b].map(n => [...n].reverse()).reduce((a, b) => a.reduce((r, d, i) => {
let s = d - (b[i] || 0)
if (s < 0) {
s += 10
a[i + 1]--
}
return '' + s + r
}, '').replace(/^0+/, ''))
すべての異なるテスト ケースを処理できるように、これらの処理には big-integer ライブラリを使用することをお勧めします。
これは、使用できる一般的なケースのためのものです....
2020年1月現在、BigInt
Javascriptにdatatypeが追加される予定です。提案は現在、ステージ 4にあります。これにより、2^53-1 (Number.MAX_SAFE_INTEGER) を超える数の正確な計算が可能になります。
BigInt は Chrome、Node、Firefox で出荷されており、Safari で進行中です。詳細はこちらをご覧ください。
var start = BigInt('1234567890123456789');
var end = BigInt('1234567890123456799');
var q = end - start;
alert(q)
BigInt は、整数リテラルの末尾に n を追加する10n
か、関数 BigInt() を呼び出すことによって作成されます。Number とも違うので 1 + 1n は失敗します。
詳細については、 MDN ページからここで読むことができます
function add(x, y) {
//*********************************************************************//
// This function adds or subtracts two extremely large decimal numbers //
// Inputs x and y should be numbers, i.e. commas are removed already //
// Use this function to remove commas and convert to number: //
// x = parseFloat(strNumber.replaceAll(",","").trim()); //
// Inputs x and y can be both positive, or both negative, //
// or a combination (i.e. one positive and one negative in any //
// position whether as x or as y) which means subtraction //
//*********************************************************************//
var temp, borrow=false, bothNeg=false, oneNeg=false, neg=false;
if (x < 0 && y < 0) { bothNeg = true; x = -x; y = -y; }
else if (x < 0 || y < 0) {
oneNeg = true;
if (Math.abs(x) == Math.abs(y)) { x = 0; y = 0; }
else if (x < 0 && Math.abs(x) > Math.abs(y)) { neg = true; x = -x; y = -y; }
else if (x < 0 && Math.abs(x) < Math.abs(y)) { temp = y; y = x; x = temp; }
else if (y < 0 && Math.abs(x) < Math.abs(y)) { neg = true; temp = y; y = -x; x = -temp; }
}
x = parseInt(x*1000000000/10).toString();
y = parseInt(y*1000000000/10).toString();
var lenx=x.length, leny=y.length, len=(lenx>leny)?lenx:leny, sum="", div=0, x1, y1, rem;
for (var i = 0; i < len; i++) {
x1 = (i >= lenx) ? 0 : parseInt(x[lenx-i-1]);
y1 = (i >= leny) ? 0 : parseInt(y[leny-i-1]);
y1 = (isNaN(y1)) ? 0 : y1;
if (oneNeg) y1 = -y1;
if (borrow) x1 = x1 - 1;
if (y < 0 && x1 > 0 && Math.abs(x1) >= Math.abs(y1)) { borrow=false; div=0; }
if (y < 0 && y1 <= 0 && (x1 < 0 || Math.abs(x1) < Math.abs(y1))) { borrow=true; rem=(x1+y1+div+10)%10; div=10; }
else { rem=(x1+y1+div)%10; div=Math.floor((x1+y1+div)/10); }
sum = Math.abs(rem).toString() + sum;
}
if (div > 0) sum = div.toString() + sum;
sum = parseFloat(sum*10/1000000000);
if (bothNeg || neg) sum = -sum;
return sum;
}