使用toFixed(2)保留两位小数后数值精度回退的问题
为什么toFixed(2)处理后数值又变回非固定精度?
问题原因
toFixed(2)返回的是字符串类型,不是数字。你第一次打印的96.74其实是字符串,但JavaScript在执行比较(change>=20)和减法(change-=20)时,会自动把字符串转成数字。- JavaScript的数字基于IEEE 754双精度浮点数标准,很多十进制小数(比如
0.1)无法被精确表示。当你对转成数字后的change做减法运算时,累积的精度误差就会显现,比如96.74 - 20 - 20实际计算结果可能变成56.739999999999995。
解决方案
方案1:用整数处理(推荐)
把所有金额转成分来计算,从根源避免浮点数精度问题:
function checkCashRegister(price, cash, cid) { // 转成分,避免浮点数误差 let change = Math.round((cash - price) * 100); console.log(change / 100); // 输出96.74 let changeArr = []; let count = 0; // 20美元等于2000分 if (change >= 2000) { while (change >= 2000 && Math.round(cid[7][1] * 100) > 0) { change -= 2000; cid[7][1] -= 20; count++; } changeArr.push(['TWENTY', 20 * count]); count = 0; } // 后续其他面额同理,全部用分单位计算 ... }
方案2:每次运算后重新固定精度
如果坚持用浮点数,每次修改change后都重新通过toFixed(2)转成数字:
function checkCashRegister(price, cash, cid) { let change = Number((cash - price).toFixed(2)); console.log(change); let changeArr = []; let count=0; if(change>=20){ while(change>=20&&cid[7][1]>0){ console.log(change); // 每次运算后重新固定两位精度 change = Number((change - 20).toFixed(2)); cid[7][1] = Number((cid[7][1] - 20).toFixed(2)); count++; } changeArr.push(['TWENTY',20*count]); count=0; } ... }
方案3:用Math.round修正精度
每次运算后用Math.round(change * 100) / 100强制保留两位小数:
function checkCashRegister(price, cash, cid) { let change = Math.round((cash - price) * 100) / 100; console.log(change); let changeArr = []; let count=0; if(change>=20){ while(change>=20&&cid[7][1]>0){ console.log(change); change = Math.round((change - 20) * 100) / 100; cid[7][1] = Math.round((cid[7][1] - 20) * 100) / 100; count++; } changeArr.push(['TWENTY',20*count]); count=0; } ... }
内容的提问来源于stack exchange,提问作者Andrew Lin
相关产品推荐
相关产品推荐

