資料精度及選型

2023-02-10 20:45:06 字數 3450 閱讀 5975

一、 為什麼關注數字精度

在大部分場景,我們預設整數或者保留兩位小數字,分別對應int和double,而沒有進一步去了解其精度,因為大部分應用,這樣的精度和資料型別是足夠應付的,但是在某些科學計數及特殊的商業範疇,可能需要更高精度的數字表達,這就要進一步了解數字的精度。大部分語言都提供兩種基本精度型別,一種是float、一種是double;實際上如果小數字如果是固定的,float和double可以想辦法轉成用int和long來表示,顯示給使用者的時候再按小數字整除,比如金額一般要求到分就可以了,那我們可以把資料設定成long,顯示的時候再除100。無論如何,如果涉及大數字、高精度的運算,可能還是饒不開使用更高精度要求的資料處理,比如:

bigdata*(smalldata*smalldata),可能理想的結果是乙個正常值,但因為精度丟失原因,兩個smalldata*smalldata可能會變成0,而讓整個計算結果相差太大,當然這種場景可能在特定的行業、物理等方面可能會碰到。

二、 精度丟失問題

一段j**a**:

float a=1f

float c=bf

結果是0.33333334

0.3333333

再來一段網上提供的案例:

public class floatdoubletest

}結果是:

f=2.0015e7

d=2.0015e7

d2=2.0014999e7

這兩個案例都發現單精度float出現了精度丟失問題,而且丟失後的資料也沒有按理想中的比如四捨五入給存保留最後一位。我們必須理解精度有資料範圍的一面,但更重要的是其精度範圍的一面。

j**a的單精度和雙精度都遵循ieee 754標準,可進一步去了維基百科大致了解下ieee 754標準

從標準來看,可總結出單雙精度和資料範圍與精度範圍。

1. 資料範圍

float和double的範圍是由指數的位數來決定的。

float的指數字有8位,而double的指數字有11位,分布如下:

float:

1bit(符號位) 8bits(指數字) 23bits(尾數字)

double:

1bit(符號位) 11bits(指數字) 52bits(尾數字)

因此,float的指數範圍為-127~+128,而double的指數範圍為-1023~+1024,並且指數字是按補碼的形式來劃分的。

其中負指數決定了浮點數所能表達的絕對值最小的非零數;而正指數決定了浮點數所能表達的絕對值最大的數,也即決定了浮點數的取值範圍。

float的範圍為-2^128 ~ +2^128,也即-3.40e+38 ~ +3.40e+38;double的範圍為-2^1024 ~ +2^1024,也即-1.

79e+308 ~ +1.79e+308。

2. 資料精度

float和double的精度是由尾數的位數來決定的。浮點數在記憶體中是按科學計數法來儲存的,其整數部分始終是乙個隱含著的「1」,由於它是不變的,故不能對精度造成影響。

float:2^23 = 8388608,一共七位,這意味著最多能有7位有效數字,但絕對能保證的為6位,也即float的精度為6~7位有效數字;

double:2^52 = 4503599627370496,一共16位,同理,double的精度為15~16位

3.範圍與精度制約關係

從上面我們知道了單雙精度float與double各自的資料範圍與精度,以float為例,如果我們控制6-7位的精度在小數點的位置上,會覺的這個是正常的應用場所。但不幸的是,實際上精度只控制高位數6-7位的精度,也就是說如果你的數字整數部分就是個大整數,那就先控制好整數部分的精度,如果速度部分超過6-7位,整數部分的精度也會丟失,更別說小數部分了。舉個極端的例子,如下**:

結果:3.4028235e38

3.4028235e38

兩者是相等的,原因大家應該都明白了,39位整數,300萬的精度差已丟失,我想現在回頭再來看一開始的兩段**,問題和原因也都明白了。

這裡還有一點,就是丟失精度的時候,並非按四捨五入等更合理的演算法,是因為這裡的元位是二進位制,規則是如果超過尾數字就會直接丟失。可以參考這篇博文:

三、 j**a的bigdecimal

j**a引入另外一種大數字型別bigdecimal,通過設定setscale可以設定精度控制,與float及double不同,這裡的精度專指小數部分的精度。

bigdecimal有多種構造方法,與精度相關最就要的三個構造方法:

bigdecimal(float param)

bigdecimal(double param)

bigdecimal(string param)

不同的引數,在構造的時候會形成預設的精度,比如float,其能控制的精度6-7位,如果引數整數部分超過7位,這時候bigdecimal構造出來的值直接就去掉了小數部分,scale也自然變0,而如果數字較小,構造出來的方法因為其很長的小數字,這時scale也變的很長。double型別的引數與float構造相似,因此看起來用double與float構造出來的方法的精度是不確定的,一般情況下採用string構造,比如

new bigdecimal(「111.111001」)

scale:6,小數後6位

new bigdecimal(「111.11100」)

new bigdecimal(「111.111」)

scale:3,多餘的0不算。

可以再次設定setscale來提高精度,比如

bigdecimal a new bigdecimal(「111.111」)

提高到6位精度

但不能降低精度,比如設成執行時會有異常,因為降低精度必須採用一種近似取值的策略,因此如果降低精度的話,bigdecimal提供了另外乙個引數, newscale,int roundingmode)。

另外bigdecimal提供了一些計算的方法,還有乙個專門用來比較兩數是否相等的方法compareto。

從功能上來說bigdecimal完全可以替代float和double來做運算使用,並且能提供精度更大的資料運算。而且bigdecimal的精度專指小數部分,對於入門者來說更容易理解。

遺憾的是bigdecimal在大資料量運算時,效率上會不如直接使用float、double;這是從網上引用的測試案例和測試資料:

import

public class bigdecimalefficiency

public static double computebydouble(double a, double b)

public static void main(string args) {

long test =

long start1 =

double result1 = computebybigdecimal(0.120000000034, 11.22);

long end1 =

long start2 =

double result2 = computebydouble(0.120000000034, 11.22);

long end2 =

監測方法及精度要求

一 一般規定 監測方法的選擇應根據基坑等級 設計要求 場地條件 場地條件 當地經驗和方法適用性等因素綜合確定,監測方法應合理易行。變形測量網的基準點 工作基點布設應符合下列要求 1 每個基坑工程至少應有3個穩固 可靠的點作為基準點 2 工作基點應選在先對穩定和方便使用的位置。在通視條件良好 距離較勁...

電纜種類及選型計算

一 電纜的定義及分類 廣義的電線電纜亦簡稱為電纜。狹義的電纜是指絕緣電纜。它可定義為 由下列部分組成的集合體,一根或多根絕緣線芯,以及它們各自可能具有的包覆層,總保護層及外護層。電纜亦可有附加的沒有絕緣的導體。我國的電線電纜產品按其用途分成下列五大類 1.裸電線 2.繞組線 3.電力電纜 4.通訊電...

線切割加工精度保證措施及方法

電火花線切割機按切割速度可分為快走絲和慢走絲兩種,由於快走絲線切割機所加工 的工件表面粗糙度一般在ra 1.25 2.5 m範圍內,而慢走絲線切割機所加工的工件表面粗 糙度通常可達到ra 0.16 m,且慢走絲線切割機的圓度誤差 直線誤差和尺寸誤差都較快 走絲線切割機好很多,所以在加工高精度零件時,...