提问人:samanthaj 提问时间:7/6/2022 最后编辑:Chrissamanthaj 更新时间:7/7/2022 访问量:53
JavaScript 中的 64 位浮点数学,为什么在这种情况下除法比乘法更好
64bit floating point math in JavaScript, why does division work better than multiplication in this situation
问:
这不是关于浮点如何工作的问题。也不是关于为什么 19.95 * 0.1 产生 19.900000000004 的问题。我已经明白浮点数学不是一个完美的演示。问题在于向专家询问他们的直觉,为什么这种特殊情况会起作用。
最近,我想将数字四舍五入到任意数量,以便进行步进滑块。我有这个代码
steppedV = Math.round(v / step) * step
我发现它不是很好,因为浮点数学问题。例如,返回v = 19.94
step = 0.1
19.900000000000002
我以为我有点不走运,但后来只是为了好玩,我尝试了这个
steppedV = Math.round(v / step) / (1 / step)
令人惊讶的是,对于我一直在使用的测试用例,它产生了更好的结果。对于与上面相同的输入,我回来了19.9
对于所有未四舍五入到我的测试步骤值的情况,它现在都正常工作。真正了解浮点数学如何工作的人可以解释为什么会产生更准确的结果而没有吗?作为一个了解浮点数学的人,这个结果直观吗?我只是运气好,还是作为专家,您知道要对(1 /步)进行除法以获得更好的结果吗?/ (1 / step)
* step
function test(start, end, inc, step) {
const addRow = makeTable(step, 'div', 'mult');
for (let v = start; v <= end; v += inc) {
const steppedVMult = Math.round(v / step) * step;
const steppedVDiv = Math.round(v / step) / (1 / step);
addRow(v, steppedVDiv, steppedVMult);
}
}
test(0, 2, 0.03, 0.1);
test(0, 0.2, 0.003, 0.01);
test(0, 0.02, 0.0003, 0.001);
test(0, 0.002, 0.00003, 0.0001);
function c(tag, children = [], text = '') {
const e = document.createElement(tag);
e.textContent = text;
children.forEach(c => e.appendChild(c));
return e;
}
function makeTable(...args) {
const makeRow = arr => c('tr', arr.map(v => c('td', [], v)));
const tbody = c('tbody');
const table = c('table', [
c('thead', [makeRow(args)]),
tbody,
]);
document.body.appendChild(table);
return function(...args) {
tbody.appendChild(makeRow(args));
};
}
body { font-family: monospace; }
table { border-collapse: collapse; margin-bottom: 10px }
thead { font-weight: bold; }
td { border: 1px solid #888; padding: 3px; }
答: 暂无答案
评论
0.1
无法用浮点数正确表示。它的确切值是 。当您在某个时候乘以这个数字时,尾随值 (..5551115...等)会参与进来。但是,无法放入 64 位浮点数的确切值,因此结果不是由于舍入,而是由于尾部小数无法放入 64 位浮点格式。0.1000000000000000055511151231257827021181583404541015625
1/0.1000000000000000055511151231257827021181583404541015625
10.000000000000000000000000000000000000000000000000
10