Esta no es una pregunta sobre cómo funciona el punto flotante. Tampoco es una pregunta sobre por qué 19.95 * 0.1 produce 19.900000000004. Ya entiendo que las matemáticas de coma flotante no son una presentación perfecta. La cuestión es más bien preguntarle a un experto su intuición por qué funciona este caso en particular.
Recientemente, quería redondear números a una cantidad arbitraria para un control deslizante escalonado. yo tenia este codigo
steppedV = Math.round(v / step) * step Descubrí que no es muy bueno debido a problemas matemáticos de punto flotante. Por ejemplo v = 19.94 step = 0.1 devuelve 19.900000000000002
Pensé que no tenía suerte, pero solo por diversión probé esto
steppedV = Math.round(v / step) / (1 / step) Y sorprendentemente, para los casos de prueba que he estado usando, está produciendo mejores resultados. Para las mismas entradas que arriba, obtengo 19.9
Para todos mis casos que no se redondearon a los valores de mi paso de prueba, todo funciona ahora. ¿Puede alguien que realmente asimila cómo funcionan las matemáticas de coma flotante explicar por qué / (1 / step) produce resultados más precisos y * step no? Como alguien que entiende las matemáticas de coma flotante, ¿este resultado es intuitivo? ¿Solo tengo suerte o, como experto, hubiera sabido hacer la división de (1 / paso) para obtener un mejor resultado?
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; }