为什么 q == 0 在以下脚本中?
<script>
var start = 1234567890123456789;
var end = 1234567890123456799;
var q = end - start;
alert(q);
</script>
我认为结果应该是 10。减去这两个数字的正确方法是什么?
为什么 q == 0 在以下脚本中?
<script>
var start = 1234567890123456789;
var end = 1234567890123456799;
var q = end - start;
alert(q);
</script>
我认为结果应该是 10。减去这两个数字的正确方法是什么?
因为 JavaScript 中的数字是浮点数。它们的精度有限。
当 JavaScript 看到一个很长的数字时,它会将它四舍五入到它可以表示为 64 位浮点数的最接近的数字。在您的脚本中,start
并end
四舍五入到相同的值。
alert(1234567890123456789); // says: 1234567890123456800
alert(1234567890123456799); // says: 1234567890123456800
没有内置方法可以对大整数进行精确算术,但您可以使用 BigInteger 库,例如this one。
杰森已经发布了原因。对于解决方案,您可以在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+/, ''))
更好地为这些事情使用大整数库,以便处理所有不同的测试用例。
这仅适用于您可以使用的一般情况....
自 2020 年 1 月起,BigInt
数据类型将添加到 Javascript。该提案目前处于第 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 页面阅读更多关于它的信息
它在JavaScript 文档中进行了解释:
根据 ECMAScript 标准,只有一种数字类型:双精度 64 位二进制格式 IEEE 754 值(介于和之间的数字)。整数没有特定的类型。
-(2
53
-1)
2
53
-1
关于双精度浮点格式的维基百科页面解释:
之间和可表示的数字恰好是整数。对于下一个范围,从到,一切都乘以,所以可表示的数字是偶数,等等。
2
52
= 4,503,599,627,370,496
2
53
= 9,007,199,254,740,992
2
53
2
54
2
(所有小于 的整数2
52
都被精确表示。)
1234567890123456789
并且1234567890123456799
大于。在这个量级上,只有大约 1% 的整数使用双精度浮点格式精确存储。2
60
= 1152921504606846976
这两个不能准确存储。它们都四舍五入到1234567890123456800
。
JavaScript 文档还解释了如何判断一个整数是否准确存储:
Number.isSafeInteger()
[...] 从 ECMAScript 6 开始,您还可以使用以及Number.MAX_SAFE_INTEGER
和来检查数字是否在双精度浮点数范围内Number.MIN_SAFE_INTEGER
。超出此范围,JavaScript 中的整数不再安全,将是该值的双精度浮点近似值。
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;
}