1. js 雙精度浮點數
一、怎樣將一個數據轉成浮點數 https://www.hu.com/question/21711083
二、js 的 Number
在 javaScript 中整數和浮點數都屬於 Number 數據類型,所有數字都是以 64 位浮點數形式儲存,即便整數也是如此。
三、造成哪些問題?
1、小數計算精度丟失,比如 0.1+0.2 不等於 0.3
2、整數最大范圍
整數是按最大54位來算最大(253 - 1,Number.MAX_SAFE_INTEGER,9007199254740991) 和最小(-(253 - 1),Number.MIN_SAFE_INTEGER,-9007199254740991) 安全整數范圍的。所以只要超過這個范圍,就會存在被捨去的精度問題。
四、解決辦法
開源的庫、bigInt、
0.1+0.2-0.3 // 5.551115123125783e-17
5.551115123125783e-17.toFixed(20) //脊顫 '0.00000000000000005551'
5.551115123125783e-17<Number.EPSILON*Math.pow(2,2) // true
重新整理
https://zhuanlan.hu.com/p/73699947
回顧一個基礎問題,js 中的精度丟失問題。
一、在 js 中只有雙精度浮點數來存儲的Number,數據存儲會有三個步驟:1、十進制轉二進制 2、二進制轉科學技術法 3、按 IEEE754 標准存儲。
二、雙精度浮點一共有 64位,64位比特又可分為三個部分:森輪
符號位S:第 1 位是正負數符號位(sign),0代表正數,1代表負數
指數位E:中間的 11 位存儲指數(exponent),用來表示次方數
尾數位M:最後的 52 位是尾數(mantissa),超出的部分自動進一櫻春敗舍零
三、基於以上知識,在數據小數位在進行轉換二進制時,會出現無線循環的情況,而數據轉成 IEEE754標准時又僅支持 52 位,所以要發生一個數據截斷,也就是精度丟失。
四、常見的丟失場景,
0.1 + 0.2 === 0.30000000000000004
parseInt(0.58*100,10)=57
(1.335).toFixed(2)
四、解決辦法
math.js
bignumber.js
等庫以及 es6 針對整數精度丟失的新數據類型BigInt
2. js浮點數精度誤差問題,解決方法
JavaScript 是一門弱類型的語言,從設計思想上就沒有對浮點數有個嚴格的數據類型,所以精度誤差的問題就顯得格外突出。下面就分析下為什麼會有這個精度誤差,以及怎樣修復這個誤差。
首先,我升坦們要站在計算機的角度思考 0.1 + 0.2 這個看似小兒科的問題。我們知道,能被計算機讀懂的是二進制,而不是十進制,所以我凳笑畢們先把 0.1 和 0.2 轉換成二進制看看:
0.1 => 0.0001 1001 1001 1001…(無限循環)
0.2 => 0.0011 0011 0011 0011…(無限循環)
雙精度浮點數的小數部分最多支持 52 位,所以兩者相加之後得到這么一串 0. 因浮點數小數位的限制而截斷的二進制數字,這時候,我們再把它轉換為十進制,就成了 0.30000000000000004。
原來如此,那怎麼解決這個問題呢?我想要的結果就是 0.1 + 0.2 === 0.3 啊!!!
有種最簡單的解決方案,就是給出明確的精度要求,在返回值的過程中,計算機會自動四捨五入,比如:
var numA = 0.1;
var numB = 0.2;
alert( parseFloat((numA + numB).toFixed(2)) === 0.3 );
乘法運算中有這棗芹種,比如0.58*100,結果是57.99999999999999。可以用Math.round()進行處理,
------||-------
盡量避免對小數進行操作,先處理成整數後在進行操作,其結果會比較精確。
3. js小數加減為什麼會失精
JavaScript的數字使用的是浮點數,浮點數可以表示的數的個數有限(只有很少一部分數可以表示),其他的數在浮點書裡面不存在
其他語言同樣有這個問題,只是在語言層面做了處理,開發者可能不需要考慮精度問題,但JavaScript語言並沒有對結果進行底層處理,所以就會有問題
提示:js的加減乘除等計算都有問題
4. JS位運算異常(位運算精度丟失)的原因探究
《【轉+補充】深入研究js中的位運算及用法》
《【JS時間戳】獲取時間戳的最快方式探究》
日常開發中一直沒遇到過位運算導致精度丟失的問題,直到這天,搞10位時間戳取整的時候,終於被我撞上了。具體是個什麼場景呢,我們來還原下案發現場:
可以看到輸出的結果為:
得到的 t 是一個精確到微秒的時間戳。但是請求介面的時候需要的是一個10位(精確到秒)的時間戳,所以這里需要將它轉換為10位,自然就是 ➗1000 即可,然後通過位運算來實現類似 Math.trunc 的取證效果,得到了我們要的10位時間戳。至此完美解決!那問題又是如何發生的呢?
按照上面的運算規律,如果我們要獲取13位時間戳,是不是直接對 t>>0 就可以了呢?我們來看一下:
輸出結果如下:
WTF!!!看到了咩!!!居然輸出了一個負數!!!我們想要的結果應該段型是 1597113682985 才對啊!為什麼會出現了負數呢!!!
由此,怪物出現啦!我們今天就來解讀(xiang fu)一下它!
想到這里,我們一定就會怪是位運算的鍋!那這個鍋該怎麼讓位運算背起來呢!我們來研究一下!
首先我們知道,JS中沒有真正的整型,數據都是以double(64bit)的標准格式存儲的,這里就不再贅述了,要想搞透其中的原理,請打開 【傳送門】
位運算是在數字底層(即表示數字的 32 個數位)進行運算的。由於位運算是低級的運算操作,所以速度往往也是最快的(相對其它運算如加減乘除來說),並且藉助位運算有時我們還能實現更簡單的程序邏輯,缺點是很不直觀,許毀伍多場合不能夠使用。
以下來源於w3shool:
ECMAScript 整數有兩種類型,即有符號整數(允許用正數和負數)和無符號整數(只允許用正數)。 在 ECMAScript 中,所有整數字面量默認都是有符號整數 ,這意味著什麼呢?
有符號整數使用 31 位表示整數的數值,用第 32 位表示整數的符號,0 表示正數,1 表示負數。數值范圍從 -2147483648 到 2147483647 。
可以以兩種不同的方式存儲二進制形式的有符號整數,一種用於存儲正數,一種用於存儲負數。 正數是以真二進制形式存儲的 ,前 31 位中的每一位都表示 2 的冪,從第 1 位(位 0)開始,表示 20,第 2 位(位 1)表示 21。沒用到的位用 0 填充,即忽略不計。例如,下圖展示的是數 18 的表示法。
那在js中二進制和十進制如何轉換呢?如下
負數同樣以二進制存儲,但使用的格式是二進制補碼。計算一個數值的二進制補碼,需要經過下列3個步驟:
例如,要確握余猜定-18的二進製表示,首先必須得到18的二進製表示,如下所示:
0000 0000 0000 0000 0000 0000 0001 0010
接下來,計算二進制反碼,如下所示:
1111 1111 1111 1111 1111 1111 1110 1101
最後,在二進制反碼上加 1,如下所示:
1111 1111 1111 1111 1111 1111 1110 1101 +
0000000000000000000000000000 0001 =
1111 1111 1111 1111 1111 1111 1110 1110
因此,-18 的二進制就是 1111 1111 1111 1111 1111 1111 1110 1110
而其相反數18的二進制為 0000 0000 0000 0000 0000 0000 0001 0010
ECMAScript會盡力向我們隱藏所有這些信息,在以二進制字元串形式輸出一個負數時,我們看到的只是這個負數絕對值的二進制碼前面加上了一個負號
JavaScript 只有一種數字類型 ( Number )
我們將 1596596596.3742654.toString(2) 轉為二進制字元串表示如下:
.0101111111001111110111
但實際在內存中的存儲如下:
說到這里就不得不簡單提一下數字精度丟失的問題。上面也知道,JS中所有的數字都是用double方式進行存儲的,所以必然會存在精度丟失問題。
以下轉自文章: JavaScript數字精度丟失問題總結
此時只能模仿十進制進行四捨五入了,但是二進制只有 0 和 1 兩個,於是變為 0 舍 1 入。這即是計算機中部分浮點數運算時出現誤差,丟失精度的根本原因。
大整數的精度丟失和浮點數本質上是一樣的,尾數位最大是 52 位,因此 JS 中能精準表示的最大整數是 Math.pow(2, 53) ,十進制即 9007199254740992
大於 9007199254740992 的可能會丟失精度:
9007199254740992 >> 10000000000000...000 ``// 共計 53 個 0
9007199254740992 + 1 >> 10000000000000...001 ``// 中間 52 個 0
9007199254740992 + 2 >> 10000000000000...010 ``// 中間 51 個 0
實際上
9007199254740992 + 1 ``// 丟失
9007199254740992 + 2 ``// 未丟失
9007199254740992 + 3 ``// 丟失
9007199254740992 + 4 ``// 未丟失
以上,可以知道看似有窮的數字, 在計算機的二進製表示里卻是無窮的,由於存儲位數限制因此存在「捨去」,精度丟失就發生了。
想了解更深入的分析可以看這篇論文(你品!你細品!): What Every Computer Scientist Should Know About Floating-Point Arithmetic
關於精度和范圍的內容可查看 【JS的數值精度和數值范圍】
通過前面的知識補充,我們已經知道:
這也就是為什麼對於整數部位為10位的時間戳,通過位運算可以進行取整(因為目前時間戳159xxxxxxx<2147483647),不存在時間戳超過范圍的問題。但是對於13位時間戳,如 1596615447123>2147483647 ,此時再通過位運算操作的時候就會導致異常,如:
這主要是因為在進行位運算之前,JS會先將64bit的浮點數 1596615447015.01 轉為32bit的有符號整型後進行運算的,這個轉換過程如下:
為了驗證上述過程,我們再舉一個例子: 1590015447015.123 >> 0 = 877547495
將將將將!沒錯的吧!所以JS的這個坑還真是。。。 讓人Orz
5. java 浮點數為什麼精度會丟失
並不是java的浮點數精度會丟失,而是所有用二進制存儲中的浮點數都可能會精度丟失(部分特殊的小數數值可以精確表示),所以計算機中存儲的浮點數都存在精度丟失的風險,不過一邊這個丟失的精度對我們正常的使用不會構成影響。
小數在轉換為二進制時並不一定能用一個精確的二進製表示,大多數時候都是取的一個近似值,這就造成了精度的丟失。如果再用這個二進制進行計算,明顯計算結果的精度會進一步丟失。
舉個簡單的例子把0.1用二進製表示(小數與二進制轉換方法)
(1)0.1x2=0.2取整數位0得0.0
(2)0.2x2=0.4取整數位0得0.00
(3)0.4x2=0.8取整數位0得0.000
(4)0.8x2=1.6取整數位1得0.0001
(5)0.6x2=0.2取整數位1得0.00011
(6)0.2x2=0.4取整數位0得0.000110
(7)0.4x2=0.8取整數位0得0.0001100
(8)0.8x2=1.6取整數位1得0.00011001
(9)0.6x2=1.2取整數位1得0.000110011
(n)...
得到一個無限循環的二進制小數 0.000110011…,沒辦法用一個精確的二進製表示0.1。而且計算機中存儲一個浮點數所用的位數也是有限的,所以只能選擇在某一個精度進行保存。
當然也有特殊的小數,比如0.25的二進制為0.01
附:代碼之謎(五)- 浮點數(誰偷了你的精度?)
6. JavaScript為什麼浮點數會丟失精度
JS浮點計算問題
問題
用js進行浮點數計算,結果可能會「超出預期」,大部分計算結果還是對的,但是我們可不想在計算這么嚴謹的事情上還有意外的驚喜。比如:
0.3 + 0.6 = 0.8999999999999999
0.3 - 0.2 = 0.09999999999999998
0.3 * 1.5 = 0.44999999999999996
0.3 / 0.1 = 2.9999999999999996
看完這幾個計算結果,如果你沒用過js,你可能會有點崩潰。我只能說,這就是js的魅力所在。
分析
在這之前,你需要知道以下幾點:
js中數字類型只有Number;
js的Number是IEEE 754標準的64-bits的雙精度數值
網上有很多關於此問題的解釋,由於計算機是用二進制來存儲和處理數字,不能精確表示浮點數,而js中沒有相應的封裝類來處理浮點數運算,直接計算會導致運算精度丟失。其實高級語言(c#,java)也存在此問題,只不過它們自己內部做了處理,把這種精度差異給屏蔽掉了。有些小數轉換為二進制位數是無窮的(有循環),但是64位中小數最多隻有52位,因此對於位數超過的相當於被截取了,導致了精度的丟失。這個地址可以用來浮點數和IEEE 754標準的64-bits的互轉(背後是二進制的轉換),用這個我們來驗證下0.3-0.2。
0.3轉換後為0.
0.2轉換後為0.
0.-0.=0.
這和js直接計算的結果0.09999999999999998想吻合。
分析下來,終於明白並不是js自身發育不良,只是沒有及時補充營養,我們只能另想出路了。
以上是網上找的
我以前遇到過問題2中瀏覽器計算的結果 是兩種,所以和瀏覽器也有問題
7. js哪些運算精度丟失
由於在H5頁面上需要進行動態的金額計算,且金額涉及到了小數,因而隨之產生了浮點數計算的精度丟失問題。
剛開始的時候,測試給提了一個金額計算誤差的問題,剛開始我還沒怎麼重視,然後瞅了瞅代碼,隨便改了改做了些異常處理,然後就給提交了。
接著,測試又提了一個bug,「6.8-0.9=5.8」。然後頓時我就蒙逼了,隨後突然意識到,JS作為解釋性語言,直接計算會有浮點數精度丟失問題。接下來,在網上找了一些資料,然後也根據具體的原理自己做了一些修改,最終解決了問題。
浮點數的二進製表示:
IEEE 754 標準是IEEE二進位浮點數算術標准(IEEE Standard for Floating-Point Arithmetic)的標准編號,等同於國際標准ISO/IEC/IEEE 60559。該標准由美國電氣電子工程師學會(IEEE)計算機學會旗下的微處理器標准委員會(Microprocessor Standards Committee, MSC)發布。這個標準定義了表示浮點數的格式(包括負零-0)與反常值(denormal number),一些特殊數值(無窮(Inf)與非數值(NaN)),以及這些數值的「浮點數運運算元」;它也指明了四種數值修約規則和五種例外狀況(包括例外發生的時機與處理方式)。
JS的浮點數實現也是遵循IEEE 754標准,採用雙精度存儲(double precision),進行了相關的實現。其中1位用來表示符號位,11位用來表示指數,52位表示尾數。
解決方案:
本質上在處理這類問題的時候,基本的思路就是通過將浮點數轉換成整數進行計算,然後再將整數的小數點位調整,轉回正確的浮點數結果。
8. js javascript 四捨五入結果不正確 不對
我測試了你的表達式,結果是3488.4849999999997。四捨五入為3488.48。
javascript做浮點數運算時,由於浮回點數精度的問題,會造成答運算結果不準確。
解決辦法是:將小數運算轉化為整數運算,這樣就不會丟失精度。
functionmultiply(arg1,arg2)
{
varm=0,s1=arg1.toString(),s2=arg2.toString();
try{
m+=s1.split(".")[1].length
}catch(e){}
try{
m+=s2.split(".")[1].length
}catch(e){}
returnNumber(s1.replace(".",""))*Number(s2.replace(".",""))/Math.pow(10,m)
}
multiply(500.50,6.97);
/*
3488.485
*/
既想保證精度,又想簡單,那沒有這樣的方法。其實這個方法本身並不復雜。
求網友推薦~
9. javascript怎麼解決浮點數計算不精確的問題
Math.add=function(v1,v2)
{
///<summary>精確計算加法。語法:Math.add(v1,v2)</summary>
///<paramname="v1"type="number">操作數。</param>
///<paramname="v2"type="number">操作數。</param>
///<returnstype="number">計算結果。</returns>
varr1,r2,m;
try
{
=v1.toString().split(".")[1].length;
}
catch(e)
{
r1=0;
}
try
{
r2=v2.toString().split(".")[1].length;
}
catch(e)
{
r2=0;
}
m=Math.pow(10,Math.max(r1,r2));
return(v1*m+v2*m)/m;
}
Number.prototype.add=function(v)
{
///<summary>精確計算加法。語法:number1.add(v)</summary>
///<paramname="v"type="number">操作數。</param>
///<returnstype="number">計算結果。</returns>
returnMath.add(v,this);
}
Math.sub=function(v1,v2)
{
///<summary>精確計算減法。語法:Math.sub(v1,v2)</summary>
///<paramname="v1"type="number">操作數。</param>
///<paramname="v2"type="number">操作數。</param>
///<returnstype="number">計算結果。</returns>
returnMath.add(v1,-v2);
}
Number.prototype.sub=function(v)
{
///<summary>精確計算減法。語法:number1.sub(v)</summary>
///<paramname="v"type="number">操作數。</param>
///<returnstype="number">計算結果。</returns>
returnMath.sub(this,v);
}
Math.mul=function(v1,v2)
{
///<summary>精確計算乘法。語法:Math.mul(v1,v2)</summary>
///<paramname="v1"type="number">操作數。</param>
///<paramname="v2"type="number">操作數。</param>
///<returnstype="number">計算結果。</returns>
varm=0;
vars1=v1.toString();
vars2=v2.toString();
try
{
m+=s1.split(".")[1].length;
}
catch(e)
{
}
try
{
m+=s2.split(".")[1].length;
}
catch(e)
{
}
returnNumber(s1.replace(".",""))*Number(s2.replace(".",""))/Math.pow(10,m);
}
Number.prototype.mul=function(v)
{
///<summary>精確計算乘法。語法:number1.mul(v)</summary>
///<paramname="v"type="number">操作數。</param>
///<returnstype="number">計算結果。</returns>
returnMath.mul(v,this);
}
Math.div=function(v1,v2)
{
///<summary>精確計算除法。語法:Math.div(v1,v2)</summary>
///<paramname="v1"type="number">操作數。</param>
///<paramname="v2"type="number">操作數。</param>
///<returnstype="number">計算結果。</returns>
vart1=0;
vart2=0;
varr1,r2;
try
{
t1=v1.toString().split(".")[1].length;
}
catch(e)
{
}
try
{
t2=v2.toString().split(".")[1].length;
}
catch(e)
{
}
with(Math)
{
r1=Number(v1.toString().replace(".",""));
r2=Number(v2.toString().replace(".",""));
return(r1/r2)*pow(10,t2-t1);
}
}
Number.prototype.div=function(v)
{
///<summary>精確計算除法。語法:number1.div(v)</summary>
///<paramname="v"type="number">操作數。</param>
///<returnstype="number">計算結果。</returns>
returnMath.div(this,v);
}
10. 關於js中小數運算丟失精度的處理辦法
浮點數值的最高精度是17位小數,但在進行運算的毀基時候其精確度卻遠遠不如整數;整數在進行運算的時候都會轉成10進制; 而java和JavaScript中計算小數運算時,都會先將十進制的小數換算到對應的二進制,一部分散高小數並不能完整的換算為二進制,這里就出現了第一次的誤差。待小數都換算為二進制後,再進行二進制間的運算,得到二進制結果。然後再將二進制結果換算為十進制,這里通常會出現第二次的誤差。
所以(0.1+0.2)!=03
解決這種問題,可以將小數變成整數進行運算,然後再將結果變為小數。
//乘法
function multiNum (a,b){
var c = 0,
d = a.toString(),
e = b.toString();
try {
c += d.split(".")[1].length;
} catch (f) { }
try {
c += e.split(".")[1].length;
} catch (f) { }
return Number(d.replace(".","")) * Number(e.replace(".","")) / Math.pow(10,c);
}
//除法
function divide (a,b){
var c,d,e = 0,
f = 0;
try {
e = a.toString().split(".")[1].length;
} catch (g) { }
try {
沖余尺 f = b.toString().split(".")[1].length;
} catch (g) { }
return c = Number(a.toString().replace(".","")),d = Number(b.toString().replace(".","")),this.mul(c / d,Math.pow(10,f - e));
}
//加法
function addNum (a,b){
var c,d,e;
try {
c = a.toString().split(".")[1].length;
} catch (f) {
c = 0;
}
try {
d = b.toString().split(".")[1].length;
} catch (f) {
d = 0;
}
return e = Math.pow(10,Math.max(c,d)),(multiNum(a,e) + multiNum(b,e)) / e;
}
//減法
function subNum (a,b) {
var c,d,e;
try {
c = a.toString().split(".")[1].length;
} catch (f) {
c = 0;
}
try {
d = b.toString().split(".")[1].length;
} catch (f) {
d = 0;
}
return e = Math.pow(10,Math.max(c,d)),(multiNum(a,e) - multiNum(b,e)) / e;
}