JavaScript解決浮點(diǎn)數(shù)計(jì)算不準(zhǔn)確問(wèn)題的方法分析
本文實(shí)例講述了JavaScript解決浮點(diǎn)數(shù)計(jì)算不準(zhǔn)確問(wèn)題的方法。分享給大家供大家參考,具體如下:
最近在學(xué)習(xí)electron框架,想利用這個(gè)框架做一個(gè)簡(jiǎn)單的計(jì)算器demo。當(dāng)我對(duì)小數(shù)進(jìn)行運(yùn)算時(shí),發(fā)現(xiàn)了一個(gè)問(wèn)題。
0.1+0.2=?
輸出結(jié)果是:0.30000000000000004。
為什么會(huì)這樣呢?
其實(shí)對(duì)于浮點(diǎn)數(shù)的四則運(yùn)算,幾乎所有的編程語(yǔ)言都會(huì)有類似精度誤差的問(wèn)題,只不過(guò)在 C++/C#/Java 這些語(yǔ)言中已經(jīng)封裝好了方法來(lái)避免精度的問(wèn)題,而 JavaScript 是一門(mén)弱類型的語(yǔ)言,從設(shè)計(jì)思想上就沒(méi)有對(duì)浮點(diǎn)數(shù)有個(gè)嚴(yán)格的數(shù)據(jù)類型,所以精度誤差的問(wèn)題就顯得格外突出。
首先我們分析一下為什么會(huì)出現(xiàn)這個(gè)精度誤差?
首先,我們要站在計(jì)算機(jī)的角度思考 0.1 + 0.2 這個(gè)看似小兒科的問(wèn)題。我們知道,能被計(jì)算機(jī)讀懂的是二進(jìn)制,而不是十進(jìn)制,所以我們先把 0.1 和 0.2 轉(zhuǎn)換成二進(jìn)制看看:
0.1 => 0.0001 1001 1001 1001..(無(wú)限循環(huán))
0.2 => 0.0011 0011 0011 0011…(無(wú)限循環(huán))
上面我們發(fā)現(xiàn)0.1和0.2轉(zhuǎn)化為二進(jìn)制之后,變成了一個(gè)無(wú)限循環(huán)的數(shù)字,這在現(xiàn)實(shí)生活中,無(wú)限循環(huán)我們可以理解,但計(jì)算機(jī)是不允許無(wú)限循環(huán)的,對(duì)于無(wú)限循環(huán)的小數(shù),計(jì)算機(jī)會(huì)進(jìn)行舍入處理。進(jìn)行雙精度浮點(diǎn)數(shù)的小數(shù)部分最多支持52位,所以兩者相加之后得到這么一串 0.0100110011001100110011001100110011001100110011001100 因浮點(diǎn)數(shù)小數(shù)位的限制而截?cái)嗟亩M(jìn)制數(shù)字,這時(shí)候,我們?cè)侔阉D(zhuǎn)換為十進(jìn)制,就成了 0.30000000000000004。
知道了浮點(diǎn)數(shù)產(chǎn)生的原因,那么如何處理這個(gè)問(wèn)題呢?
方法1:通過(guò)toFixed(num)方法來(lái)保留小數(shù)。因?yàn)檫@個(gè)方法是根據(jù)四舍五入來(lái)保留小數(shù)的,所以最后的計(jì)算結(jié)果不精確。
方法2:把要計(jì)算的數(shù)字升級(jí)(乘以10的n次冪)成計(jì)算機(jī)能夠精確識(shí)別的整數(shù),計(jì)算完以后再降級(jí),推薦使用這一種方法。具體代碼如下(主要有3個(gè)方法):
/*判斷obj是否為一個(gè)整數(shù)*/
function isInteger(obj){
return Math.floor(obj) === obj;
}
/**
* 將一個(gè)浮點(diǎn)數(shù)轉(zhuǎn)換成整數(shù),返回整數(shù)和倍數(shù)
* 如 3.14 》》314 倍數(shù)是100
*
*/
function toInteger(floatNum){
var ret = {times:1,num:0};
//是整數(shù)
if(isInteger(floatNum)){
ret.num = floatNum;
return ret;
}
var strfi = floatNum + '';
//查找小數(shù)點(diǎn)的下標(biāo)
var dotPos = strfi.indexOf('.');
console.log('dotPos===='+dotPos);
//獲取小數(shù)的位數(shù)
var len = strfi.substr(dotPos+1).length;
console.log('len===='+len);
//Math.pow(10,len)指定10的len次冪。
var time = Math.pow(10,len);
//將浮點(diǎn)數(shù)轉(zhuǎn)化為整數(shù)
var intNum = parseInt(floatNum*time + 0.5,10);
console.log('intNum===='+intNum);
ret.times = time;
ret.num = intNum;
return ret;
}
/**
*進(jìn)行運(yùn)算
*三個(gè)參數(shù)分別是要運(yùn)算的兩個(gè)數(shù)和運(yùn)算符
*/
function operation(a,b,op){
var o1 = toInteger(a);
var o2 = toInteger(b);
var n1 = o1.num;
var n2 = o2.num;
var t1 = o1.times;
var t2 = o2.times;
var max = t1 > t2 ? t1 : t2;
var result = null;
switch(op){
case 'add':
if(t1 === t2){
result = n1 + n2;
}else if(t1 > t2){
result = n1 + n2 * (t1/t2);
}else{
result = n1 * (t2/t1) + n2;
}
return result / max;
break;
case 'subtract':
if(t1 === t2){
result = n1 - n2;
}else if(t1 > t2){
result = n1 - n2 * (t1/t2);
}else{
result = n1 * (t2/t1) - n2;
}
return result / max;
break;
case 'multiply':
result = (n1 * n2)/(t1 * t2);
return result;
break;
case 'divide':
result = (n1 / n2)/(t2 / t1);
return result;
break;
}
}
更多關(guān)于JavaScript相關(guān)內(nèi)容感興趣的讀者可查看本站專題:《JavaScript數(shù)學(xué)運(yùn)算用法總結(jié)》、《JavaScript數(shù)據(jù)結(jié)構(gòu)與算法技巧總結(jié)》、《JavaScript數(shù)組操作技巧總結(jié)》、《JavaScript事件相關(guān)操作與技巧大全》、《JavaScript操作DOM技巧總結(jié)》及《JavaScript字符與字符串操作技巧總結(jié)》
希望本文所述對(duì)大家JavaScript程序設(shè)計(jì)有所幫助。
- javascript將浮點(diǎn)數(shù)轉(zhuǎn)換成整數(shù)的三個(gè)方法
- 跟我學(xué)習(xí)javascript的浮點(diǎn)數(shù)精度
- 深入理解JavaScript中的浮點(diǎn)數(shù)
- JavaScript浮點(diǎn)數(shù)及運(yùn)算精度調(diào)整詳解
- 詳解JS-- 浮點(diǎn)數(shù)運(yùn)算處理
- 詳解JavaScript 浮點(diǎn)數(shù)運(yùn)算的精度問(wèn)題
- JS實(shí)現(xiàn)的進(jìn)制轉(zhuǎn)換,浮點(diǎn)數(shù)相加,數(shù)字判斷操作示例
- JS中浮點(diǎn)數(shù)精度問(wèn)題的分析與解決方法
- 處理JavaScript浮點(diǎn)數(shù)精度問(wèn)題的解決方案
- JavaScript 浮點(diǎn)數(shù)精度問(wèn)題小結(jié)
相關(guān)文章
javascript單例模式的簡(jiǎn)單實(shí)現(xiàn)方法
這篇文章主要介紹了javascript單例模式的簡(jiǎn)單實(shí)現(xiàn)方法,以javascript創(chuàng)建唯一實(shí)例的形式分析了javascript單例模式的簡(jiǎn)單實(shí)現(xiàn)技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下2015-07-07
JavaScript數(shù)據(jù)分析之交集,并集,對(duì)稱差集
這篇文章主要介紹了JavaScript數(shù)據(jù)分析之交集,并集,對(duì)稱差集,文章圍繞主題展開(kāi)詳細(xì)的內(nèi)容介紹,具有一定的參考價(jià)值,需要的小伙伴可以參考一下2022-07-07
獲取當(dāng)前點(diǎn)擊按鈕的id用this.id實(shí)現(xiàn)
這篇文章主要介紹了獲取當(dāng)前點(diǎn)擊按鈕的id的方法,,需要的朋友可以參考下2014-03-03
bootstrap Table服務(wù)端處理分頁(yè)(后臺(tái)是.net)
這篇文章主要為大家詳細(xì)介紹了bootstrap Table服務(wù)端處理分頁(yè),后臺(tái)是.net,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-10-10
window.print()前端實(shí)現(xiàn)網(wǎng)頁(yè)打印功能詳解
JavaScript 函數(shù)window.print()可用于打印你的應(yīng)用的內(nèi)容,但是它針對(duì)的是使用默認(rèn)打印體驗(yàn)打印顯示在屏幕上的內(nèi)容,這篇文章主要給大家介紹了關(guān)于window.print()前端實(shí)現(xiàn)網(wǎng)頁(yè)打印功能的相關(guān)資料,需要的朋友可以參考下2024-04-04
一文詳解如何用原型鏈的方式實(shí)現(xiàn)JS繼承
JavaScript中,每當(dāng)創(chuàng)建一個(gè)對(duì)象,都會(huì)給這個(gè)對(duì)象提供一個(gè)內(nèi)置對(duì)象 [[Prototype]] 。這個(gè)對(duì)象就是原型對(duì)象,[[Prototype]] 的層層嵌套就形成了原型鏈。本文將詳細(xì)講解如何用原型鏈的方式實(shí)現(xiàn)一個(gè) JS 繼承,感興趣的可以了解下2022-04-04
JavaScript實(shí)現(xiàn)給對(duì)象添加一個(gè)只讀屬性
這篇文章主要為大家介紹了JavaScript如何給對(duì)象加一個(gè)只讀屬性,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-06-06
使用?Angular?服務(wù)器端渲染?Transfer?State?Service
這篇文章主要介紹了使用?Angular?服務(wù)器端渲染?Transfer?State?Service,假設(shè)我們使用?Angular?Universal?開(kāi)發(fā)一個(gè)服務(wù)器端渲染的?Angular?應(yīng)用,這個(gè)應(yīng)用會(huì)消費(fèi)一個(gè)第三方的?Restful?API2022-06-06
微信小程序?qū)崿F(xiàn)列表頁(yè)的點(diǎn)贊和取消點(diǎn)贊功能
這篇文章主要為大家詳細(xì)介紹了微信小程序?qū)崿F(xiàn)列表頁(yè)的點(diǎn)贊和取消點(diǎn)贊功能,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-11-11

