最為一個常識,我們都知道浮點型在內存中占用的是 4 個字節的空間,而 long 型占用的是 8 個字節的空間。可是為什么 4 個字節的 float 型的最大值會大於 long 型的最大值呢?
我們都知道,float 類型的范圍是:一 3.403E38~3.403E38。而 long 類型的范圍是:-2^63~2^63-1(大概是 9*10^18)。
我以前也是簡單的記住就算完事了,對於它為什么會這樣卻沒有考慮過。
下面給大家分享一下我現在的理解:
long 整型數,在內存中占用 8 個字節共 64 位,它表示的數值有 2 的 64 次方,平分正負,數值范圍是負 2 的 63 次方到正 2 的 63 次方 - 1。
而 float 在內存中占 4 個字節,共 32 位,但是浮點數在內存中是這樣的:
V=(-1)^s * M * 2^E
667x190
浮點數的 32 位不是簡單的直接表示大小,而是按照一定的標准分配的。
其中第 1 位,符號位,即 S。
接下來的 8 位,指數域,即 E。
剩下的 23 位,小數域,即 M,M 的取值范圍為 [1,2)或 [0,1)。
也就是說,浮點數在內存中的二進制值不是直接轉換為十進制數值的,而是按照上述公式計算而來,通過這個公式,雖然只用到了 4 個字節,但是浮點數卻比長整型的最大值要大。
這也就是為什么在數據轉換的時候,long 類型轉換為 float 類型的根本原因所在!
一個數據在計算機的內存中保存時,需要一定的空間,這種 “空間” 由程序中的“數據類型”(比如 int/long/float)來告訴編譯器。
在數據類型所占用的空間范圍內的數據,可以進行類型轉換或者強制類型轉換,也許會有一些誤差,但一般不會出現離奇的 “錯誤的結果”
另外,占用空間小的數據類型(比如 int)向占用空間大的數據類型(比如 long)轉換,一般也不會出現 “錯誤的結果”
但是反過來,占用空間大的數據類型向小的數據類型轉換時,由於有可能會丟失數據的精度,所以編譯器會提示錯誤;這個時候可以選擇強制類型轉換,但有時會得到 “意想外的結果”
Java 中規定:
int 占用 4 個字節
long 占用 8 個字節
float 占用 4 個字節
int 和 long 的轉換很容易理解,
4 個同學去有 4 張床位的寢室和去有 8 張床位的寢室,都能很好的容納;
8 個同學去有 8 張床位的寢室,沒有問題;去僅有 4 張床位的寢室就容納不下了。
樓主問的問題可以轉化為:為什么 long 型占用 8 個字節,但相對於僅占用 4 個字節的 float 時的行為卻很像 “小數據類型”
(為什么 long 可以轉換為 float,而反過來 float 轉換為 long 時,有時會出問題)
Java 語言數據類型之間的合法轉換
6 個實心箭頭代表無數據丟失的轉換
3 個虛心箭頭代表可能有精度損失的轉換
沒有箭頭的代表通常不能進行轉換
(參考:JAVA 核心技術 卷 I:基礎知識 圖 3-1)
核心技術的作者給出的例子如下:
int n = 123456789;
float f = n; // f is 1.23456792E8
從 n 到 f 轉換時,雖然得到了同樣大小的結果,但卻失去了一定的精度。
說白了就是 long 型雖然占用 8 個字節,但是由於要非常嚴密精確的表達每一位數,
能夠表達的數的范圍,反倒沒有占用 4 個字節的 float 型能夠表達的數據范圍大
