JavaScript浮點運算0.2+0.1 !== 0.3

浮點運算JavaScript

本文主要討論JavaScript的浮點運算,主要包括

  • JavaScript number基本類型

  • 二進制表示十進制

  • 浮點數的精度

number 數字類型

在JavaScript中,數字只有number這一種類型;

var intS = 2,floatA = 0.1;
typeof intS;   // number
typeof floatA; //number

那么這個情況下應該很容易理解一件事情:number應該是實現的浮點型數來標識所有的數;
而實際上也是這樣;JavaScript的number類型按照ECMA的JavaScript標準,它的Number類型就是IEEE 754的雙精度數值,相當于java的double類型。IEEE 754標準《二進制浮點數算法》(www.ieee.org)就是一個對實數進行計算機編碼的標準。

十進制轉換為二進制

同樣,在計算機的世界里,應該是只有二進制數據的,不是0就是1,那么為了表達生活中最為常見的十進制數據,就會有個轉換過程;這個就是十進制轉換為二進制的方法;
參考:http://www.cnblogs.com/xkfz00...

十進制整數轉換為二進制

這個情況比較常見:3 =》 01;5 =》101;十進制整數轉換為二進制整數采用"除2取余,逆序排列"法。具體做法是:用2去除十進制整數,可以得到一個商和余數;再用2去除商,又會得到一個商和余數,如此進行,直到商為零時為止,然后把先得到的余數作為二進制數的低位有效位,后得到的余數作為二進制數的高位有效位,依次排列起來
換算的法則是,使用一個十進制數字來示例: 173 =》 10101101:
圖片描述

十進制小數變為二進制

十進制的小數轉換為二進制,0.5 =》 0.1 ;十進制小數轉換成二進制小數采用"乘2取整,順序排列"法。具體做法是:用2乘十進制小數,可以得到積,將積的整數部分取出,再用2乘余下的小數 部分,又得到一個積,再將積的整數部分取出,如此進行,直到積中的小數部分為零,或者達到所要求的精度為止。然后把取出的整數部分按順序排列起來,先取的整數作為二進制小數的高位有效位,后取的整數作為低位有效位。
示例 0.8125 =》 0.1101
圖片描述

完整的十進制小數轉為二進制

從上面的講述中可以知道,一個十進制的小數:173.8125 轉換為二進制是 10101101.1101;在計算機中一般都會使用科學計算來處理浮點數,也就是 173.8125 == 1.738125 * 10(2);那么二進制的表示也不例外,通過指數來定位小數點,用固定的精度來表示數據;

在JavaScript使用的IEEE 754的雙精度數值,一個JavaScript的number表示應該是二進制如下格式:

 1[-/+] 11[位指數]        52[數值]                 64位長
+  -  + -------- + ----------------------- +

64位的具體表述在不同系統可能順序會有差異,但是都是包含以下三部分:

  1. 符號位: 1bit,0表示正數,1表示負數

  2. 指數位:11bit,也就是需要移動的位數,也就是指數的大小;由于會存在負數和證書,所以這里用了一個偏移的方式處理,也就是真正的指數+1023,這樣的話就表示了【-1023 ~ 1024】;而-1023也就是全0,1024就是全1;

  3. 尾數:52bit,這里需要注意的是由于小數點前面以為必須為1,所以實際上是52+1=53位;

參考:http://coolcao.com/2016/10/12...
http://www.cnblogs.com/kingwo...
可以看到,由于二進制的精確位數只有52+1位,那么類似 1/3 這樣的無理數,那么肯定是無法表示的,而且二進制還有很多有理數 0.1這樣的也無法在52位精度的范圍內表示精確無誤;都會被截取53位以后的所有數字。

0.1+0.2 !== 0.3 [true]

有了以上的鋪墊,那么我們很容易就可以推到出原因了;推理步驟如下:

十進制0.1 =》 [利用上面說的方法來轉換,乘以2取整數,然后順序獲取取出得數]

 =>二進制為:0.0001100110011[0011…](循環0011,無限循環)   =>指數表示:尾數為1.1001100110011001100…1100(共52位,除了小數點左邊的必須為1的數據),指數為-4(-4+1023 = 1019 二進制移碼為 01111111011),符號位為0  => 計算機存儲為:0 01111111011 10011001100110011…11001  => 因為尾數最多52位,所以實際存儲的值為0.00011001100110011001100110011001100110011001100110011001  

而十進制0.2

 => 二進制0.0011001100110011…(循環0011)  =>尾數為1.1001100110011001100…1100(共52位,除了小數點左邊的1),指數為-3(-3+1023=1020二進制移碼為01111111100),符號位為0  => 存儲為:0 01111111100 10011001100110011…11001  因為尾數最多52位,所以實際存儲的值為0.00110011001100110011001100110011001100110011001100110011  

 那么兩者相加得:
加法運算的時候需要注意以下幾點:

  • 對階:需要將指數小的,變得和指數大的一樣,通過位數移位【移位注意有一個隱藏的小數點左邊的固定的1】

  • 尾數運算:加法運算

  • 結果規格化:規范為 位數的左邊第一位必須為隱藏的1,

  • 舍入處理:主要是在截取的時候進行的處理,最后位舍去時為0直接舍去,為1則+1;【有多種舍入處理】

  • 溢出判斷:

尾數加法運算開始,注意小數點左邊隱藏的默認1

   [1].1001100110011001100110011001100110011001100110011001+ [1].1001100110011001100110011001100110011001100110011001

//由于0.1是-3階,指數是-4,而0.2的指數位-3,故而取大者-3;這樣0.1需要右移一位,剛好之前小數點左側隱藏的1被移出來了;如下

      .1100110011001100110011001100110011001100110011001100 【1被舍去】
+  [1].1001100110011001100110011001100110011001100110011001
=   100110011001100110011001100110011001100110011001100111

此時階碼變為了 -3,但是由于進位了兩位,但是最高位需要保留,故而階位只是+1,也就是-2了.也就是01111111101,
進行舍入處理,由于最高位一定是1,所以對結果最高位去除,末尾一位去除,由于是1,故而+1處理,得到新的52位位數為:

 新的尾數: 0011001100110011001100110011001100110011001100110100
存儲為: 0  01111111101  0011001100110011001100110011001100110011001100110100
十進制就是:0.3000000000000000444089209850062616169452667236328125
截取為:   0.30000000000000004  

轉換成10進制之后得到:0.30000000000000004

思考

看到 0.1+0.2 = 0.30000000000000004;我開始慌了,那么0.1+0.3 === 0.4 對嗎?我也不知道,雖然最后運算的時候證明是對的,但是還是可以按照我們的方法進行分析

 十進制0.1  [利用上面說的方法來轉換,乘以2取整數,然后順序獲取取出得數]=>二進制為:0.0001100110011[0011…](循環0011,無限循環)   =>指數表示:尾數為1.1001100110011001100…1100(共52位,除了小數點左邊的必須為1的數據),指數為-4(-4+1023 = 1019 二進制移碼為 01111111011),符號位為0  => 計算機存儲為:0 01111111011 10011001100110011…11001  => 因為尾數最多52位,所以實際存儲的值為0.00011001100110011001100110011001100110011001100110011001 而十進制0.3  => 二進制0.010011001100110011001100110011001...(循環1001)  =>尾數為1.00110011001100110011…0011(共52位,除了小數點左邊的1),指數為-2(-2+1023=1021二進制移碼為01111111101),符號位為0  => 存儲為:0 01111111101 0011001100110011…110011  因為尾數最多52位,所以實際存儲的值為0.01001100110011001100110011001100110011001100110011001100  那么兩者相加得[對階,為大者-2,-4階數的0.1左移兩位]:      .0110011001100110011001100110011001100110011001100110
+ [1].0011001100110011001100110011001100110011001100110011 
=   1.1001100110011001100110011001100110011001100110011001新的尾數: 1001100110011001100110011001100110011001100110011001
存儲為: 0  01111111101  1001100110011001100110011001100110011001100110011001
十進制就是:0.39999999999999996447286321199499070644378662109375
截取為:   0.4 

可以看到,JavaScript的小數保留了17位,

//一個52位小數的最小二進制的表示
0.0000000000000000000000000000000000000000000000000001
0.0000000000000002220446049250313 
//一個53【加頭部默認1位】位小數的最小二進制數
0.00000000000000000000000000000000000000000000000000001
0.00000000000000011102230246251565
Math.pow(2, 53)
9007199254740992 //當大于這個數的時候就會丟失精度
Math.pow(2, -53)
1.1102230246251565e-16  //當小于這個數也會丟失精度

JavaScript采用了17位來默認截取數據,根據四舍五入方法或者是說二進制中的0舎1進位的方式截取。
所以這樣的加法有的時候會出現精度問題,有的又不會。看看具體的情況,在chrome的console里面運行的結果如下:

0.4-0.1
0.300000000000000040.3+0.1
0.40.1+0.2
0.30000000000000004

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/394636.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/394636.shtml
英文地址,請注明出處:http://en.pswp.cn/news/394636.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

html獲取data-*值,html5 獲取和設置data-*屬性值的四種方法講解

1、獲取id的對象2、需要獲取的就是data-id 和 dtat-vice-id的值一:getAttribute()方法const getId document.getElementById(getId);// //getAttribute()取值屬性console.log(getId.getAttribute("data-id"));//console.log(getId.getAttribute("da…

三菱模擬量輸入與輸出程序_初學PLC是學習西門子還是三菱?

PLC的種類繁多,品牌大多分為歐系、日系、美系。德系PLC以西門子為主,日系有三菱、歐姆龍、松下……,美系有羅克韋爾(A-B)通用電氣(GE)公司、莫迪(MODICON)公司等。美國和歐洲的PLC技術是在相互隔離情況下獨立研究開發的,因此美國和…

性能測試十四:Xshell鏈接linux虛擬機

一、先裝一個linux虛擬機 VBoxcentos1、先下載Linux鏡像文件的ovf或者OVA文件2、打開vbox,點擊菜單欄“管理”-“導入虛擬電腦3、選擇解壓路徑中的ovf或者OVA文件,點擊下一步 4、點擊“導入”,等待完成5、導入成功后,選擇新導入的…

代碼編寫工具_我希望在開始編寫代碼時就已經知道的工具:已復習

代碼編寫工具by Mario Hoyos通過馬里奧霍約斯(Mario Hoyos) 我希望在開始編寫代碼時就已經知道的工具:已復習 (Tools I wish I had known about when I started coding: Revisited) A few days ago, I wrote this article for freeCodeCamp which has since gone o…

Hydra掃描姿勢

參數詳解: -R 根據上一次進度繼續破解 -S 使用SSL協議連接 -s 指定端口 -l 指定用戶名 -L 指定用戶名字典(文件) -p 指定密碼破解 -P 指定密碼字典(文件) -e 空密碼探測和指定用戶密碼探測(ns) -C 用戶名可以用:分割(username:password)可以代替-l username -p pass…

html5進度條插件 傳遞參數,Html5進度條插件(自寫)

(function () {window.H5ProgressBar function (obj) {this.height obj.height;this.width obj.width;this.speed obj.speed;};//在界面上布局元素H5ProgressBar.prototype.drawLayout function () {document.write("開始下載")document.write(" ")do…

python合并txt文本_Python實現將目錄中TXT合并成一個大TXT文件的方法

本文實例講述了Python實現將目錄中TXT合并成一個大TXT文件的方法。分享給大家供大家參考。具體如下: 在網上下了一個dota的英雄攻略,TXT格式,每個英雄一個文件,看得疼,就寫了一個小東西,合并一下. #codinggbk import os import sys import glob def dirTxtToLargeTx…

讀取字符串中的數字和小數

package com.jm.label.tools;import java.util.Map;import java.util.TreeMap;import java.util.regex.Matcher;import java.util.regex.Pattern;/** * 讀取字符串中的數字和小數 * author JM.H * */public class DigitUtil { public static String getNumber(String str){ …

html網頁設計要點,網站交互設計的8個要點

一、力求一致性例如網站首頁需要和每一個下級頁面保持一致的風格,導航都要放在屏幕的左上角,具有高度一致性的界面能給人清晰整潔的感覺。二、允許頻繁使用快捷鍵快捷鍵表示產品使用的靈活性和有效性,想想每次我們使用搜索引擎的時候是鼠標點…

行為擴展以及插件機制

在thinkPHP中的行為擴展和插件機制。 首先行為擴展這個概念是TP框架的核心組成之一,關于行為的解釋我就粗略的概括一下吧: TP在從接受到HTTP請求到最終將試圖輸出,期間經歷的很多步驟,這些步驟大家可以在http://document.thinkphp…

python android 庫_Python庫

Gevent Gevent是一個基于greenlet的Python的并發框架,以微線程greenlet為核心,使用了epoll事件監聽機制以及諸多其他優化而變得高效。 于greenlet、eventlet相比,性能略低,但是它封裝的API非常完善,最贊的是提供了一個…

ios 應用商店_如何在預算范圍內制作值得應用商店使用的iOS應用預覽

ios 應用商店Back in 2014, Apple made it possible to add an app preview to the the App Store. App previews are the best way to show potential users what your app has to offer before they download the app. In fact, users are 3x more likely to install an app …

搭建nfs共享存儲服務之二nfs服務端配置

1.1.NFS服務端配置文件路徑為: /etc/exports,并且默認為空,需要用戶自行配置。/etc/exports文件配置格式為:NFS共享的目錄 NFS客戶端地址1(參數1,參數2...)客戶端地址2(參數1&#x…

計算機word基本知識選擇題,2017計算機基礎考試選擇題「附答案」

2017計算機基礎考試選擇題「附答案」一、單項選擇題(每題1.5分,共30分)1、文件名使用通配符的作用是(b)A、減少文件名所占用的磁盤空間B、便于一次處理多個文件C、便于給一個文件命名D、便于保存文件2、操作系統是一種(a)A、系統軟件 B、系統程序庫 C、編譯程序系統…

[JLOI2015]管道連接(斯坦納樹)

[Luogu3264] 原題解 多個頻道,每個頻道的關鍵點要求相互聯通 詳見代碼,非常巧妙 #include<cstdio> #include<iostream> #include<cstring> #include<algorithm> #include<queue> #define debug(...) fprintf(stderr,__VA_ARGS__) #define Debug(…

關于web前端的學習路線

第一階段&#xff1a; HTMLCSS:HTML進階、CSS進階、divcss布局、HTMLcss整站開發、 JavaScript基礎&#xff1a;Js基礎教程、js內置對象常用方法、常見DOM樹操作大全、ECMAscript、DOM、BOM、定時器和焦點圖。 JS基本特效&#xff1a;常見特效、例如&#xff1a;tab、導航、整頁…

值大于為此列指定的允許精度_電能質量測試精度會受到哪些因素影響?如何解決?...

關于電能質量&#xff08;也稱為PQ:Power Quality&#xff09;研究的主題已成為多方面的話題。其需要考慮的不僅僅是IEC 61000-x-x電磁兼容性標準中規定的實際電能質量現象。在實踐中&#xff0c;通常還會增加其他重要參數來保證供電的安全性&#xff0c;在某些情況下這些參數甚…

SEO博客

http://www.chinamyhosting.com/seoblog/分類: SEO 本文轉自快樂就好博客園博客&#xff0c;原文鏈接&#xff1a;http://www.cnblogs.com/happyday56/archive/2008/05/10/1191435.html&#xff0c;如需轉載請自行聯系原作者

gis計算各省河流長度_用河流和各方解釋安全漏洞

gis計算各省河流長度by Andrea Zanin由Andrea Zanin 用河流和各方解釋安全漏洞 (Security Vulnerabilities Explained with Rivers and Parties) Security vulnerabilities can be boring to learn. But you still need to learn them, unless you want some hacker to delete…

Delphi關于記錄文件的操作

http://www.cnblogs.com/railgunman/archive/2010/08/16/1801004.html Delphi關于記錄文件的操作 本例子幾個變量的說明TFileRec record   //記錄定義Day : Integer;...          //其他定義end;f : File of TFileRec;   //標準的輸入/輸出文件FilRec : TFileR…