計算機中的浮點數在數軸上分布均勻嗎?
比如一個32位機的float浮點數 如果在數軸上把所有可表示的值表示出來 在數軸上是否是均勻的?
@vczh 的例子不夠誇張,IEEE754中,里的浮點數比里的浮點數多。
#include &
#include &
#include &
using namespace std;
// Count number of float in [l, r)
unsigned frange(float l, float r) {
assert(l &>= 0.0f r &>= 0.0f);
float f = l;
unsigned n = 0;
do {
f = nextafter(f, r);
n++;
} while (f != r);
return n;
}
float utof(unsigned x) {
union { unsigned u; float f; } u = { x };
return u.f;
}
int main(int argc, char* argv[]) {
cout &<&< "[0, 2): " &<&< frange(0.0f, 2.0f) &<&< endl;
cout &<&< "[2, inf): " &<&< frange(2.0f, INFINITY) &<&< endl;
cout &<&< "[0, MinNormal): " &<&< frange(0.0f, utof(0x00800000)) &<&< endl;
cout &<&< "[MinNormal, 1.0): " &<&< frange(utof(0x00800000), 1.0f) &<&< endl;
cout &<&< "[1.0, inf): " &<&< frange(1.0f, INFINITY) &<&< endl;
}
// [0, 2): 1073741824
// [2, inf): 1065353216
// [0, MinNormal): 8388608
// [MinNormal, 1.0): 1056964608
// [1.0, inf): 1073741824
--
更新:為了回答 @陳碩在評論中的問題,修改了一下程序,並畫出以下的表。可見,的個數是的倍,原因是8-bit exponent有0xFF這特殊值,用於表示inf和NaN,所以exponent可表示非特殊值的是奇數,導至exponent的正負個數並非相等。
最近正好在對比浮點數據和整型數據分別適合處理什麼類型的計算,這是16bit = s(1bit).e(6 bits).f(9 bits)格式在範圍內的分布,縱軸使用的是log坐標,絕對值越小的數表示的越精確。
當然不是均勻的,1-2裡面的所有浮點數,就跟2-4裡面的所有浮點數一樣多
謝謝邀請。這個問題挺有意思的。
依據最常見的IEEE標準,把所有float32在數軸上標出來,會長什麼樣子呢?
首先,浮點數的表示範圍(拋去正無窮和負無窮)是有限的,所以被標出的數軸只是數軸中的一段。因此大尺度上肯定不是均勻分布的。
其次,由於浮點數的原理是科學計數法,所以(大體上講),表示的是所有有效數字恰好為一定數目的數,所以,在相同的數量級上是均勻的,但在不同的數量級上就不是了。
綜上,浮點數在數軸上的分布不是絕對均勻的,而是分段均勻的。
(另外,這個問題和操作系統內核並無關係。內核里一般是禁止使用浮點數的。)如果你取對數作為橫坐標的話,那就是在每個整數區間之間都是均勻的。整數區間之內是線性刻度均勻的。
我們可以把符號位忽略掉,只看正半軸。然後我們按,等等一直到在數軸上畫點。這樣每兩個相鄰點之間所含的浮點數表示量是一樣的。
另外,在和之間只有零能表示出來。
也就是說,除去到這一段,越靠近零的地方是會分布的越密的。
參考ARM Information Center - 庫和浮點支持指南
@Milo Yip的解答很直觀。我來對結果做些理論解釋。
下圖是IEEE754單精度浮點數在內存中的表示法。綠色部分為指數部分,紅色部分為尾數部分。這個表示法的具體解讀可以參考float的精範圍是如何求出來的? - 坡下碎石的回答。 只考慮正數情況時,最高位的符號位為0。2.0f的表示方法如下圖。這時指數部分為128,尾數為0。當指數部分小於128時,不管尾數是多少,這個值都小於2.0f。當所有位都為0時表示0.0f。因此0~29位均可取0或1,可以表示的0到2.0之間的浮點數為2^30 = 1073741824。
而正無限的表示法如下圖所示,指數部分為255,尾數有個隱藏位為1。那麼指數在128到255之間,尾數任意取值,這樣就是IEEE754單精度浮點數可以表示的2到正無窮之間的數。一共有2^30 - 2 ^ 23 = 1065353216個。回到本題,我們可以從上面的表示法看出來,每個指數取值所能表示的數為2^23個,從0開始指數每增長1,其表示數的範圍就增長1倍,但可以表示的數是一樣多的。所以浮點數在數軸上的分布應該符合對數規律,即取對數後接近均勻分布。
浮點數的設計目的就是整數位小,需要較少bit表示時可以騰出更多bit表示小數位,所以必然不均勻。
不均勻。越靠近原點越密集,越遠離原點越稀疏。
這問題問的好專業我看了半天。
我要舉例子上解釋這個問題了哈前方低能。首先套用某匿名答案,計算機中浮點數的「浮點」就是可以移動的小數點的位置。那麼我們來假設一個浮點數只有8byte而且點不佔位同時沒有負數來簡化理解這個問題。好的讓我們設定這8byte分別是76543210,而點的位置就有可能為.7.6.5.4.3.2.1.0. 就是這個樣子。在8byte的整數區間,我們可以表示最小0,最大255的整數,而這個時候我們的小數點是固定在8byte中的最後的。當我們的點數位於0後衛,數值為76543210. 咱滴浮點數,精度是1.
讓我們移動一下這個浮點數的點,讓我們的數值變為7654321.0 咱滴浮點數,精度是0.5,最大值127.5最小值0.以此類推!
當我們吧數值變為.76543210的時候,咱滴浮點數,精度是1/2的次冪,也就是256分之1.最大值lim-&>1等於255/256,最小值0。也就是說在我們的浮點數在點可能的9個位置上的精度分別為1、0.5、0.25、0.125、0.0625、0.03125、0.015625、0.0078125和0.00390625。顯而易見,我們的浮點位分布為:0-&>1 256個1-&>2 128個2-&>3 64個4-&>5 32個
8-&>9 16個16-&>17 8個32-&>33 4個64-&>65 2個128-&>129 1個函數繪圖分布:請腦補。那麼我們來進行一下拓展,8byte拓展為64byte,同時加入一個符號位佔位,加入一個階符,加入一個階碼。在進行計算,原理是完全完全完全一樣的。所以答案是不平均而且成指數墜落。可以簡單理解為:整數部分越小,那麼小數部分能表示的就越多,數量自然越多,所以0-1的數量是最多的。
浮點數的「浮」的意思就是那個小數點可以動。有效數字就那麼多,整數部分長點兒,小數部分就短了。在數軸上取固定長度的一段兒,如果靠近0,那麼數比較小,整數部分比較短,小數部分比較長,這段兒包含的數的個數就多了。
貢獻點代碼,作為對 @Milo Yip答案的補充
#include &
#include &
using namespace std;
/*
* f &>= 0.0f;
*/
float nextFloat(float f) {
struct float_in_memory {
unsigned int tail : 23;
unsigned int exp : 8;
unsigned int sign : 1;
};
float_in_memory fim = *((struct float_in_memory*)f);
/*
* It"s same with:
* int i = *((int *)f);
* i++;
* f = *((float *)i);
*/
if (fim.tail == 0x7fffff) {
fim.tail = 0;
fim.exp++;
} else {
fim.tail++;
}
f = *((float *)fim);
return f;
}
int main() {
int n = 0;
float f = 0.0f;
while (f &< 2.0f) {
f = nextFloat(f);
n++;
}
cout &<&< "float in [0,2) is " &<&< n &<&< endl;
n = 0;
while (f &< INFINITY) {
f = nextFloat(f);
n++;
}
cout &<&< "float in [2, infinity) is " &<&< n &<&< endl;
return 0;
}
如果均勻分布,又不止一個的話,就有無窮多個,顯然是不可能的啊
IEEE 754 標準已經很多人提過了。不再贅述。針對 64bits dobule 而言,1 bit 符號位(sign),11 bits 指數位(exponent),52 bits 尾數位(mantissa)。但其實我不喜歡說浮點數是小數點在浮動這個說法,感覺像是主動去動這個小數點。回到浮點數的定義 里,所謂小數點浮動是 大數字相乘帶來的被動結果。
直接看浮點數的話,我覺得最方便的還是 MATLAB,可以直接用 format hex 展示浮點數 16 進位的樣子。介紹點有用的。
realmax,64位浮點數最大的數,是 7fefffffffffffff,約等於 1.7977e+308。
realmin,64位浮點數最小的數,是 0010000000000000,約等於 2.2251e-308。
精度問題的話,具體到不同區間 ,精度(增長步長)為 。其中 t 是保存 mantissa 的 bits 數,這裡是 52。可以看出來數字越小精度越大,當 e &>= 53 的時候,步長就已經大於 1 了。所以會出現 這種情況,體現到 MATLAB 里就是&>&> 2^53 == 2^53 + 1
ans = 1
&>&> 2^52 == 2^52 + 1
ans = 0
僅[-1,1] 區間就佔了50%的有效浮點數值
同類型浮點數的「有效位數」是一樣多的
只允許有3位有效數字
比1.23大一點點的是1.24比123000.0大一點點是124000.0題主你說呢
哦,對了,上面的例子用的是十進位,請腦補成二進位版本例子可以看csapp第2章關於浮點數的內容。
推薦閱讀:
※Rust目前有比較靠譜的IDE嗎?
※集線器和交換機的區別?
※勸退偽化生和傳統工科並推崇CS是不是知乎上的一種政治正確?為什麼會這樣呢?
※如果出現一種實用的新型計算機(未來計算機,比如基於憶阻器的),那麼需要學習新的編程語言么?
※在軟體開發的職業領域裡,在什麼樣的情況下才會遇到 : 計算機編程藝術《The Art of Computer Programming》以及 演算法導論《Introduction to Algorithms》 中的知識呢?