摘要:按照的數(shù)字格式,整數(shù)有的范圍是,而且只能表示有限個(gè)浮點(diǎn)數(shù),能表示的個(gè)數(shù)為個(gè)。
0.1+0.2 等于0.3嗎?相信拿著這條題目隨便問(wèn)一個(gè)高年級(jí)的小學(xué)生,他們都會(huì)毫不猶豫都回答:相等。是的,相等是正常的,這是常識(shí)。但是都說(shuō)實(shí)踐是檢驗(yàn)真理的唯一標(biāo)準(zhǔn),拿這道簡(jiǎn)單的算術(shù)題用javascript在chrome控制臺(tái)試驗(yàn)一下:
結(jié)果令人大跌眼鏡,在控制臺(tái)輸入0.1+0.2 == 0.3返回的結(jié)果竟然是false!!!!我們輸入0.1+0.2,看看結(jié)果,竟然是0.30000000000000004。
這是為什么呢?在《Javascript權(quán)威指南》中有提到,JS是不區(qū)分整數(shù)和浮點(diǎn)數(shù)的,JS采用的是IEEE 754標(biāo)準(zhǔn)定義的64位浮點(diǎn)格式表示數(shù)字,所以JS中的所有數(shù)字都是浮點(diǎn)數(shù)。按照J(rèn)S的數(shù)字格式,整數(shù)有的范圍是-2^53 ~ 2^53,而且只能表示有限個(gè)浮點(diǎn)數(shù),能表示的個(gè)數(shù)為2^64 ? 2^53 + 3個(gè)。至于為什么是這個(gè)范圍,可以具體看看《JavaScript 中的數(shù)字》這篇文章也解下。而我們都知道,浮點(diǎn)數(shù)的個(gè)數(shù)是無(wú)限的,這就導(dǎo)致了JS不能精確表達(dá)所有的浮點(diǎn)數(shù),而只能是一個(gè)近似值。
那怎樣才能比較0.1+0.2 == 0.3呢?既然浮點(diǎn)數(shù)是一個(gè)近似值,那我們可以認(rèn)定在某個(gè)可以接受的精度范圍內(nèi),他們是相等的。因此可以定義一個(gè)比較函數(shù)來(lái)比較浮點(diǎn)數(shù)。
function isFloatEqual(f1,f2,digits) { return f1.toFixed(digits) === f2.toFixed(digits); } isFloatEqual(0.1+0.2,0.3,10); // 返回true
可以看到,這時(shí)再比較0.1+0.2就與0.3相等了。這種比較,其實(shí)是字符串的比較,toFixed方法,返回的是一個(gè)字符串。可以在控制臺(tái)中輸入:
0.1.toFixed(1)+0.2.toFixed(1)
你會(huì)發(fā)現(xiàn),返回的結(jié)果是"0.10.2"
這種方法解決了0.1+0.2==0.3的問(wèn)題,但是當(dāng)我用isFloatEqual(0.3 - 0.2,0.1,10)的時(shí)候,發(fā)覺(jué)返回的值是false,這又是為什么呢?
原來(lái)0.3 - 0.2計(jì)算出來(lái)的是0.09999999999999998,上面的方法只能覆蓋到計(jì)算結(jié)果比實(shí)際結(jié)果大的情況,而對(duì)于小的情況無(wú)能為力。
我們知道,當(dāng)兩個(gè)數(shù)相減,如果差在約定的精度范圍內(nèi),我們就可以認(rèn)為這兩個(gè)數(shù)相等,根據(jù)這個(gè)原理,再來(lái)重寫(xiě)isFloatEqual函數(shù),如下:
function isFloatEqual(f1,f2,digits) { return Math.abs(f1 - f2) < digits; } isFloatEqual(0.1+0.2,0.3,0.001); // true isFloatEqual(0.3-0.2,0.1,0.001); // true
那除了上面的方法外,能不能讓JS在做加減法的時(shí)候精確一點(diǎn)呢?
我們知道,只要在-2^53 ~ 2^53的范圍內(nèi),JS做整數(shù)的加減運(yùn)算是精確的,那么我們是不是可以將浮點(diǎn)數(shù)轉(zhuǎn)換為整數(shù),再進(jìn)行運(yùn)算呢?按照這個(gè)思路,在《淺談JavaScript浮點(diǎn)數(shù)及其運(yùn)算》這篇文章中,提供了一種方法,將代碼粘貼如下:
function accAdd(arg1,arg2){ var r1,r2,m; try{r1=arg1.toString().split(".")[1].length}catch(e){r1=0} try{r2=arg2.toString().split(".")[1].length}catch(e){r2=0} m=Math.pow(10,Math.max(r1,r2)) return (arg1*m+arg2*m)/m }
這種方法是先計(jì)算出兩個(gè)浮點(diǎn)數(shù)的小數(shù)位數(shù)n,兩個(gè)參數(shù)再分別與10^n(放大倍數(shù))相乘,以達(dá)到對(duì)兩個(gè)參數(shù)取整的目的,再用整數(shù)來(lái)進(jìn)行相加運(yùn)算,加完后除掉放大的倍數(shù)就可以得出結(jié)果了。
現(xiàn)在用accAdd(0.1,0.2),返回的結(jié)果是0.3了,但是評(píng)論里面馬上有人提出accAdd(2.22,0.1) 的結(jié)果不是2.32,而是2.3200000000000003。原來(lái)在做arg1*m這一步時(shí),依舊是浮點(diǎn)數(shù)運(yùn)算,所以返回的結(jié)果不一定是整數(shù),依舊是浮點(diǎn)數(shù)。
我看到作者在做減法的時(shí)候用了toFixed(),如果用toFixed(n)是不是就可以了呢?來(lái)試一下,函數(shù)改造成這樣:
function accAdd(arg1,arg2){ var r1,r2,n,m; try{r1=arg1.toString().split(".")[1].length}catch(e){r1=0} try{r2=arg2.toString().split(".")[1].length}catch(e){r2=0} n = Math.max(r1,r2); m=Math.pow(10,n); return ((arg1*m+arg2*m)/m).toFixed(n) }
這次再調(diào)用accAdd(2.22,0.1)時(shí),返回的是2.32了,完美!
但是手賤試了下accAdd(2.22,0.08),返回的結(jié)果是2.30,而我期望返回的結(jié)果是2.3。上文已經(jīng)提到過(guò),toFixed返回的是一個(gè)字符串,所以用toFixed返回2.30看來(lái)是正常的了。那如果要返回2.3要怎樣做呢?
其實(shí)很簡(jiǎn)單,用parseInt將arg1*m轉(zhuǎn)換為整數(shù)就可以了。
function accAdd(arg1,arg2){ var r1,r2,m; try{r1=arg1.toString().split(".")[1].length}catch(e){r1=0} try{r2=arg2.toString().split(".")[1].length}catch(e){r2=0} m=Math.pow(10,Math.max(r1,r2)) return (parseInt(arg1*m,10)+parseInt(arg2*m,10))/m }參考文章
JavaScript 中的數(shù)字
淺談JavaScript浮點(diǎn)數(shù)及其運(yùn)算
What Every JavaScript Developer Should Know About Floating Points
近期在看《javascript權(quán)威指南》,邊看邊總結(jié),都會(huì)同步發(fā)送到微信公眾號(hào)上,歡迎關(guān)注,歡迎提意見(jiàn):
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/91050.html
摘要:標(biāo)準(zhǔn)是浮點(diǎn)數(shù)算術(shù)標(biāo)準(zhǔn)的標(biāo)準(zhǔn)編號(hào),等同于國(guó)際標(biāo)準(zhǔn)。標(biāo)準(zhǔn)規(guī)定了計(jì)算機(jī)程序設(shè)計(jì)環(huán)境中的二進(jìn)制和十進(jìn)制的浮點(diǎn)數(shù)之間的交換算術(shù)格式以及方法。 初學(xué)JavaScript,在進(jìn)行小數(shù)(浮點(diǎn)數(shù))運(yùn)算時(shí),經(jīng)常會(huì)碰到這樣的情況:0.1 + 0.2=0.30000000000000004,記得當(dāng)時(shí),教程告訴我們說(shuō),0.1 + 0.2在JavaScript運(yùn)算中,它的值是不固定的,可以在后面學(xué)習(xí)和試驗(yàn)中,漸漸...
摘要:方法使用定點(diǎn)表示法來(lái)格式化一個(gè)數(shù),會(huì)對(duì)結(jié)果進(jìn)行四舍五入。該數(shù)值在必要時(shí)進(jìn)行四舍五入,另外在必要時(shí)會(huì)用來(lái)填充小數(shù)部分,以便小數(shù)部分有指定的位數(shù)。如果數(shù)值大于,該方法會(huì)簡(jiǎn)單調(diào)用并返回一個(gè)指數(shù)記數(shù)法格式的字符串。在環(huán)境中,只能是之間,測(cè)試版本為。 showImg(https://segmentfault.com/img/remote/1460000011913134?w=768&h=521)...
摘要:返回是,這是為什么呢我們知道浮點(diǎn)數(shù)計(jì)算是不精確的,上面的返回式實(shí)際上是這樣的在的新規(guī)范加入了一個(gè)新的東西是在對(duì)象上面,新增一個(gè)極小的常量。根據(jù)規(guī)格,它表示與大于的最小浮點(diǎn)數(shù)之間的差。上面的代碼為浮點(diǎn)數(shù)運(yùn)算,部署了一個(gè)誤差檢查函數(shù)。 0.1+0.2 === 0.3 //返回是false, 這是為什么呢?? 我們知道浮點(diǎn)數(shù)計(jì)算是不精確的,上面的返回式實(shí)際上是這樣的:0.1 + 0.2 = ...
摘要:的二進(jìn)制科學(xué)計(jì)數(shù)法第位是,所以就有了下面的結(jié)果有著同樣的問(wèn)題,其實(shí)正是由于這樣的存儲(chǔ),在這里有了精度丟失,導(dǎo)致了。最大安全數(shù)字中表示最大安全數(shù)字計(jì)算結(jié)果是,即在這個(gè)數(shù)范圍內(nèi)不會(huì)出現(xiàn)精度丟失小數(shù)除外這個(gè)數(shù)實(shí)際上是。是一個(gè)任意精度的整數(shù)。 話不多說(shuō),先上代碼 function judgeFloat(n, m) { const binaryN = n.toString(2...
摘要:標(biāo)準(zhǔn)二進(jìn)制浮點(diǎn)數(shù)算法就是一個(gè)對(duì)實(shí)數(shù)進(jìn)行計(jì)算機(jī)編碼的標(biāo)準(zhǔn)。然后把取出的整數(shù)部分按順序排列起來(lái),先取的整數(shù)作為二進(jìn)制小數(shù)的高位有效位,后取的整數(shù)作為低位有效位。 浮點(diǎn)運(yùn)算JavaScript 本文主要討論JavaScript的浮點(diǎn)運(yùn)算,主要包括 JavaScript number基本類型 二進(jìn)制表示十進(jìn)制 浮點(diǎn)數(shù)的精度 number 數(shù)字類型 在JavaScript中,數(shù)字只有numb...
閱讀 3237·2021-09-07 10:10
閱讀 3582·2019-08-30 15:44
閱讀 2582·2019-08-30 15:44
閱讀 2997·2019-08-29 15:11
閱讀 2225·2019-08-28 18:26
閱讀 2748·2019-08-26 12:21
閱讀 1116·2019-08-23 16:12
閱讀 3027·2019-08-23 14:57