下面是三个函数,每个函数都做同样的事情,但有点不同。它们都将数组中的数字相乘并返回结果。但有一种奇怪的行为,有人可以解释一下有什么不同。
function _mreduce0(name) {
return name.split('').reduce((acc, e) => {
return acc * 31 * e.charCodeAt(0);
}, 7);
}
function _mreduce1(name) {
let nArr = name.split('');
let acc = 7;
for (let i = 0; i < nArr.length; i += 1) {
acc *= 31 * nArr[i].charCodeAt(0);
}
return acc;
}
function _mreduce2(name) {
let nArr = name.split('');
let acc = 7;
for (let i = 0; i < nArr.length; i += 1) {
acc = acc * 31 * nArr[i].charCodeAt(0);
}
return acc;
}
let n = 'somename';
console.log(_mreduce0(n) === _mreduce1(n)); // true
console.log(_mreduce0(n) === _mreduce2(n)); // true
// It is good for small size but when the string is large there is difference.
n = 'e868831414410da6b0b416be7e80f5211765ad4d1aed295cd24fcc17e72c03fc';
console.log(_mreduce0(n) === _mreduce1(n)); // false
console.log(_mreduce0(n) === _mreduce2(n)); // true
答案 0 :(得分:1)
Javascript只有一个类型 - 数字 - 而数字总是浮点类型。
它的意思是什么?它实际上可以跳过一些数字,或者没有精确的结果,计数太大,太低或十进制数。
什么是&#34;太大&#34;?有这个值:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/MAX_SAFE_INTEGER
如果你超过这个值(而你这样做),你就不能使用原生的javascript号码(你可以,但你可以得到不准确的结果)
答案 1 :(得分:1)
通常乘法是关联的,但在一种情况下,javascript引擎看起来像a = a*b; a = a*c;
,而在另一种情况下它看起来tmp = (b*c); a = a*tmp;
。在这两种情况下都会发生算术溢出,但是以不同的方式使它们的行为不同。
以下是显示相同效果的序列。差异发生,然后甚至自我解决,重新发生等等。
var x = 7;
var y = 7;
console.log(x === y);
for (var i = 1; i < 50; i++) {
x *= 31 * 3;
y = y * 31 * 3;
console.log('i = ' + i + ' -> ' + (x === y ? "equal" : "diff: " + (x - y)));
}
&#13;
如果我们将其更改为使用y = y * 93
,则永远不会有任何区别:
var x = 7;
var y = 7;
console.log(x === y);
for (var i = 1; i < 50; i++) {
x *= 31 * 3;
y = y * 93;
console.log('i = ' + i + ' -> ' + (x === y ? "equal" : "diff: " + (x - y)));
}
&#13;
我的结论是y = y * 31 * 3
从左到右计算右前端,每个*
后可能出现算术错误效应。
y *= 31 * 3
实际上也是这样做的,但右侧是31 * 3
=== 93
,然后乘以y
。
答案 2 :(得分:1)
比较1
和2
怎么样?这也是错误的,所以看起来0
和2
正在做类似的事情。 acc *=
表达式似乎是罪魁祸首。
请参阅:Why are shortcuts like x += y considered good practice?
您在迭代8开始溢出,因为值不匹配。
7.43088268730786e+26 !== 7.430882687307858e+26
这两个数字之间的差异是137,438,953,472。
var valTable, n = 'e868831414410da6b0b416be7e80f5211765ad4d1aed295cd24fcc17e72c03fc';
valTable = [];
console.log('Are they the same?:', _mreduce0(n) === _mreduce2(n)); // true
console.log(displayValues(valTable));
valTable = [];
console.log('Are they the same?:', _mreduce0(n) === _mreduce1(n)); // false
console.log(displayValues(valTable));
function _mreduce0(name) {
return name.split('').reduce((acc, e, i) => {
var val = acc * 31 * e.charCodeAt(0);
addToTable(valTable, i, 0, val); // Control
return val;
}, 7);
}
function _mreduce1(name) {
let nArr = name.split(''), acc = 7;
for (let i = 0; i < nArr.length; i += 1) {
acc *= 31 * nArr[i].charCodeAt(0);
addToTable(valTable, i, 1, acc); // Loop 1
}
return acc;
}
function _mreduce2(name) {
let nArr = name.split(''), acc = 7;
for (let i = 0; i < nArr.length; i += 1) {
acc = acc * 31 * nArr[i].charCodeAt(0);
addToTable(valTable, i, 1, acc); // Loop 2
}
return acc;
}
function addToTable(table, row, col, val) {
if (table.length < row + 1) table.push([val]); else table[row][col] = val;
}
function displayValues(table) {
return table.map((v, i) => [i, v[0] === v[1] ? 'yes' : 'no', v[0], v[1]].join('\t')).join('\n');
}
.as-console-wrapper { top:0; max-height:100% !important;}