float和double有什麼區別?

kelexin發表於2020-12-08

float和double在遊戲行業肯定是用的很多的,雖然這是個很基礎的問題,但是面試時被問到還是感覺說的不是很好。
所以還是總結一下:

float 單精度浮點數在機內佔 4 個位元組,用 32 位二進位制描述。

double 雙精度浮點數在機內佔 8 個位元組,用 64 位二進位制描述。

浮點數在機內用指數型式表示,分解為:數符,尾數,指數符,指數四部分。

數符佔 1 位二進位制,表示數的正負。

指數符佔 1 位二進位制,表示指數的正負。

尾數表示浮點數有效數字,0.xxxxxxx, 但不存開頭的 0 和點。

指數存指數的有效數字。

指數佔多少位,尾數佔多少位,由計算機系統決定。

可能是數符加尾數佔 24 位,指數符加指數佔 8 位 -- float。

數符加尾數佔 48 位,指數符加指數佔 16 位 -- double。

知道了這四部分的佔位,按二進位制估計大小範圍,再換算為十進位制,就是你想知道的數值範圍。

對程式設計人員來說,double 和 float 的區別是 double 精度高,有效數字 16 位,float 精度 7 位。但 double 消耗記憶體是 float 的兩倍,double 的運算速度比 float 慢得多,
C 語言中數學函式名稱 double 和 float 不同,不要寫錯,能用單精度時不要用雙精度(以省記憶體,加快運算速度)。

簡單來說,Float 為單精度,記憶體中佔 4 個位元組,有效數位是 7 位(因為有正負,所以不是8位),在我的電腦且 VC++6.0 平臺中預設顯示是6位有效數字;double為 雙精度,佔 8 個位元組,有效數位是 16 位,但在我的電腦且 VC++6.0 平臺中預設顯示同樣是 6 位有效數字

例子:在 C 和 C++ 中,如下賦值語句:

float a=0.1; 

編譯器報錯:warning C4305: 'initializing' : truncation from 'const double ' to 'float '

原因: 在 C/C++ 中(也不知道是不是就在 VC++ 中這樣),上述語句等號右邊 0.1,我們以為它是個 float,但是編譯器卻把它認為是個 double(因為小數預設是 double),所以要報這個 warning,一般改成 0.1f 就沒事了。

本人通常的做法,經常使用 double,而不喜歡使用 float。

C 語言和 C# 語言中,對於浮點型別的資料採用單精度型別 float 和雙精度型別 double 來儲存,float 資料佔用 32bit, double 資料佔用 64bit,我們在宣告一個變數 float f= 2.25f 的時候,是如何分配記憶體的呢?如果胡亂分配,那世界豈不是亂套了麼,其實不論是 float 還是 double 在儲存方式上都是遵從 IEEE 的規範 的,float 遵從的是 IEEE R32.24 ,而 double 遵從的是 R64.53。

無論是單精度還是雙精度在儲存中都分為三個部分:

符號位(Sign):0 代表正,1 代表為負。
指數位(Exponent):用於儲存科學計數法中的指數資料,並且採用移位儲存。
尾數部分(Mantissa):尾數部分。

特別注意:

當你不宣告的時候,預設小數都用double來表示,所以如果要用float的話,則應該在其後加上f

例如:float a=1.3;

則會提示不能將double轉化成float 這成為窄型轉化

如果要用float來修飾的話,則應該使用float a=1.3f

注意float是8位有效數字,第7位數字將會產生四捨五入

所以如果一個float變數 這樣定義: float a=1.32344435; 則第7位將產生四捨五入(5及5以下的都將捨去)

1.兩個在定義時的區別

(1)float型 記憶體分配4個位元組,佔32位,範圍從10-38到1038 和 -1038到-10-38

例float x=123.456f,y=2e20f; 注意float型定義的資料末尾必須有"f"或"F",為了和double區別

(2)double型 記憶體分配8個位元組,範圍從10-308到10308 和 -10-308到-10-308
例:double x=1234567.98,y=8980.09d; 末尾可以有"d"也可以不寫

2、特別需要注意的是兩個浮點數的算術運算

直接使用 +,-,*,%運算子的問題

 public class Test{
        public static void main(String args[]){
        System.out.println(0.05+0.01);
        System.out.println(1.0-0.42);
        System.out.println(4.015*100);
        System.out.println(123.3/100);
        }
    }

結果:

0.060000000000000005
0.5800000000000001
401.49999999999994
1.2329999999999999

原因:

首先得從計算機本身去討論這個問題。我們知道,計算機並不能識別除了二進位制資料以外的任何資料。無論我們使用何種程式語言,在何種編譯環境下工作,都要先把源程式翻譯成二進位制的機器碼後才能被計算機識別。
以上面提到的情況為例,我們源程式裡的2.4是十進位制的,計算機不能直接識別,要先編譯成二進位制。但問題來了,2.4的二進位制表示並非是精確的2.4,反而最為接近的二進位制表示是2.3999999999999999。原因在於
浮點數由兩部分組成:指數和尾數,這點如果知道怎樣進行浮點數的二進位制與十進位制轉換,應該是不難理解的。如果在這個轉換的過程中,浮點數參與了計算,那麼轉換的過程就會變得不可預知,並且變得不可逆。
我們有理由相信,就是在這個過程中,發生了精度的丟失。而至於為什麼有些浮點計算會得到準確的結果,應該也是碰巧那個計算的二進位制與十進位制之間能夠準確轉換。而當輸出單個浮點型資料的時候,可以正確輸出,如

double d = 2.4;
System.out.println(d);

輸出的是2.4,而不是2.3999999999999999。也就是說,不進行浮點計算的時候,在十進位制裡浮點數能正確顯示。
這更印證了我以上的想法,即如果浮點數參與了計算,那麼浮點數二進位制與十進位制間的轉換過程就會變得不可預知,並且變得不可逆。

事實上,浮點數並不適合用於精確計算,而適合進行科學計算。這裡有一個小知識:既然float和double型用來表示帶有小數點的數,那為什麼我們不稱它們為“小數”或者“實數”,要叫浮點數呢?因為這些數都以科學計數法的形式儲存。
當一個數如50.534,轉換成科學計數法的形式為5.053e1,它的小數點移動到了一個新的位置(即浮動了)。可見,浮點數本來就是用於科學計算的,用來進行精確計算實在太不合適了。

參考:
https://my.oschina.net/zd370982/blog/724265
https://www.jb51.net/article/159043.htm

相關文章