搜尋
首頁常見問題double浮點數運算為啥會失去精確度

double浮點數運算為啥會失去精確度

Jun 26, 2019 am 09:15 AM
double浮點數

double浮點數運算為啥會失去精確度

前言:在工作中,談到有小數點的加減乘除都會想到用BigDecimal來解決,但是有很多人對於double或者float為啥會丟失精度一臉茫然。還有BigDecimal是怎麼解決的?話不多說,我們開始吧。

1.浮點數是啥?

 浮點數是電腦用來表示小數的資料型,採用科學計數法。在java中,double是雙精度,64位,浮點數,預設是0.0d。 float是單一精確度,32位元.浮點數,預設為0.0f;

double浮點數運算為啥會失去精確度

## 在記憶體中儲存

float      符號位元(1bit)   指數(8 bit)     尾數(23 bit)

double     尾數(23 bit)
double   符號位元(1bit)  關係式(11 bit)   尾數(52 bit)


float在記憶體中指數是8bit,由於階碼實際儲存的是


float,記憶體中指數是8bit,由於階碼實際儲存的是##float指數的移碼,假設指數的真值是e,階碼為E,則有E=e (2^n-1 -1)。其中 2^n-1 -1是IEEE754標準規定的指數偏移量,根據這個公式我們可以得到 2^8 -1=127。於是,float的指數範圍為-128    127,而double的指數範圍為-1024   1023。其中負指數決定了浮點數所能表達的絕對值最小的非零數;而正指數決定了浮點數所能表達的絕對值最大的數,也即決定了浮點數的值範圍。

float的範圍為-2^128 ~ 2^127,也即-3.40E 38 ~ 3.40E 38;

double的範圍為-2^1024 ~ 2^1023,也即-1.79E 308 ~ 1.79E 308

2.走進失真之科學計數法

 我們先說說科學計數法,科學計數法是一種簡化計數的方法,用來近似表示一個極大或極小且位數較多的數,對於位數較小的數值,科學計數法沒有什麼優勢,但對於位數較多的數值其計數方法的優勢就非常明顯了。例如:光的速速是300000000公尺/秒,全世界人口數大約是6100000000。類似光的速度和世界人口數這樣大數值的數,讀、寫都很不方便,所以光的速度可以寫成3*10^8,全世界人口數可以寫成6.1*10^9。所以計算機用科學計數法表示光速是3E8,世界人口數大約是6.1E9。

double浮點數運算為啥會失去精確度我們小時候玩計算器喜歡瘋狂的累加或累減,到最後計算器就會顯示下圖。這就是科學計數法顯示的結果 

那圖真實的值是  -4.86*10^11=-486000000000。十進制科學計數法要求有效數字的整數部分必須在【1,9】區間內。

 

3.走進失真之精確度

double浮點數運算為啥會失去精確度電腦在處理資料都涉及到資料的轉換和各種複雜運算,例如,不同單位換算,不同進制(如二進制十進制)換算等,很多除法運算不能除盡,例如10÷3=3.3333.....無窮無盡,而精度是有限的,3.3333333x3並不等於10,經過複雜的處理後得到的十進制數據並不精確,精度越高越精確。 float和double的精度是由尾數的位數來決定的,其整數部分始終是一個隱含著的“1”,由於它是不變的,故不能對精度造成影響。 float:2^23 = 8388608,一共七位,由於最左為1的一位省略了,這意味著最多能表示8位數: 28388608 = 167777216 。有8位有效數字,但絕對能保證的為7位,也即float的精度為7~8位有效數字;double:2^52 = 4503599627370496,一共16位,同理,double的精度為16~17位元.

當到達某一值自動開始使用科學計數法,並保留相關精確度的有效數字,所以結果是個近似數,並且指數為整數。在十進制中小數有些是無法完整用二進位表示的。所以只能用有限位元來表示,從而在儲存時可能會有誤差。對於十進制的小數轉換成二進制採用乘2取整法進行計算,取掉整數部分後,剩下的小數繼續乘以2,直到小數部分全為0。

double浮點數運算為啥會失去精確度如遇到 

輸出是 0.19999999999999998


double型別 0.3-0.1的情況。需要將0.3轉成二進位在運算


0.3 * 2 = 0.6 => .0 (.6)取0剩0.6
0.6 * 2 = 1.2 => .01 (. 2)取1剩0.2
0.2 * 2 = 0.4 => .010 (.4)取0剩0.4

0.4 * 2 = 0.8 => .0100 (.8) 取00.8## #0.8 * 2 = 1.6 => .01001 (.6)取1剩0.6###.............###

 double浮點數運算為啥會失去精確度

 

3.總​​結

  看完上面,大概清楚了為啥浮點數會有精確度問題。簡單來說float和double類型主要是為了科學計算和工程計算而設計,他們執行二進制浮點運算,這是為了在廣泛的數值範圍上提供較為精確的快速近和計算而精心設計的。然而,他們並沒有提供完全精確的結果,所以不應該被用於精確的結果的場合。浮點數達到一定大的數會自動使用科學計數法,這樣的表示只是近似真實數而不等於真實數。當十進制小數位轉換二進制的時候也會出現無限循環或超過浮點數尾數的長度。
 

4.那我們要怎麼用BigDecimal來解?

大家看下面的兩個輸出

double浮點數運算為啥會失去精確度

輸出結果:

0.299999999999999988897769753748434595763683319091796832##.阿里的程式碼約束外掛程式已經標註警告,讓我使用String參數的建構方法來建立BigDecimal。因為double不能精確地表示為0.3(任何有限長度的二進位),所以構造方法傳遞的值也是不完全等於0.3。大家在使用BigDecimal的時候一定要用String參數的建構方法來建立。說到這裡,是木頭有還有好奇的寶寶有疑問,BigDecimal的原理是啥?為啥它就沒有問題呢?其實原理很簡單,BigDecimal是不可變的,可以用來表示任意精確度的帶符號十進位數。 double之所以會出問題,是因為小數點轉二進位遺失精確度。 BigDecimal在處理的時候把十進制小數擴大N倍讓它在整數上進行計算,並保留相應的精度資訊。至於BigDecimal是怎麼保存的可以翻閱一下原始碼。

更多常見問題的相關技術文章,請造訪

常見問題

欄位進行學習!

以上是double浮點數運算為啥會失去精確度的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

Video Face Swap

Video Face Swap

使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱門文章

熱工具

MinGW - Minimalist GNU for Windows

MinGW - Minimalist GNU for Windows

這個專案正在遷移到osdn.net/projects/mingw的過程中,你可以繼續在那裡關注我們。 MinGW:GNU編譯器集合(GCC)的本機Windows移植版本,可自由分發的導入函式庫和用於建置本機Windows應用程式的頭檔;包括對MSVC執行時間的擴展,以支援C99功能。 MinGW的所有軟體都可以在64位元Windows平台上運作。

禪工作室 13.0.1

禪工作室 13.0.1

強大的PHP整合開發環境

Dreamweaver Mac版

Dreamweaver Mac版

視覺化網頁開發工具

DVWA

DVWA

Damn Vulnerable Web App (DVWA) 是一個PHP/MySQL的Web應用程序,非常容易受到攻擊。它的主要目標是成為安全專業人員在合法環境中測試自己的技能和工具的輔助工具,幫助Web開發人員更好地理解保護網路應用程式的過程,並幫助教師/學生在課堂環境中教授/學習Web應用程式安全性。 DVWA的目標是透過簡單直接的介面練習一些最常見的Web漏洞,難度各不相同。請注意,該軟體中

Dreamweaver CS6

Dreamweaver CS6

視覺化網頁開發工具