簡單來說,一般計算機的整數運算是模算數(modular arithmetic)。例如8 位無符號整數的運算結果是模除256,若要計算 [公式] ,就會是 [公式] 。運算溢出時只會設置進位標記(carry flag)。這樣的好處之一,是可以實現比 CPU 寄存器長度更大的運算,例如用32位CPU做 64 位的加減法,可以分開兩次32位運算來做。這需要模算數。

而浮點數是用於近似地表示實數(real number),它不需支持模算數。相反,它最好支持溢出(overflow)和下溢(underflow)。在 IEEE 754中,選擇了用 [公式] 表示實數線上兩個方向的溢出,[公式] 表示實數線上兩個方向的下溢。[1] 里有一個例子說明實際應用,假設有一數學表達式:

[公式]

考慮其單邊極限:

[公式]

但如果單邊極限的方向不一樣(如 [公式] ),結果是未定義的。

IEEE 754 的規則可以很好的表現這兩種情況:

  1. a / +0.0 = +infa &> 0.0
  2. a / +inf = +0.0 a &> 0.0
  3. (+inf) + (+inf) = +inf
  4. (+inf) + (-inf) = nan

例如 x = +0, y = +0,運用以上的規則,計算過程將為:

[公式]

我們可以用一個 C 程序驗證一下:

#include &

double f(double x, double y) {
return 1.0 / (1.0 / x + 1.0 / y);
}

int main() {
printf("%lg
", f( 0.0, 0.0));
printf("%lg
", f( 0.0, -0.0));
printf("%lg
", f(-0.0, 0.0));
printf("%lg
", f(-0.0, -0.0));
}

編譯執行:

$ gcc a.c ./a.out
0
nan
nan
-0

總括而言,這個溢出/下溢的表示方式以及相關的運算規則,令一般的應用能比較接近數學的表示方式。這也解釋了為什麼 IEEE 754 中有 +0 和 -0 兩個零。

[1] Hough, David. "Applications of the proposed ieee 754 standard for floating-point arithetic." Computer 3 (1981): 70-74.


其實浮點數的表達也有很多種,後來被標準化,我們一般最常討論的是 IEEE 754 標準。

有一些特殊值確實是後加入的。至於浮點數為什麼要有特殊值,根據我的理解,是因為浮點數是一種實現、或稱為一種表示法,它用於表達實數(理論上全範圍的實數,實際上受限於精度,32 位 64 位或者處理器內部的 80 位都可以用同一種思路)。而實數在計算的時候,不可避免地會出現特殊情況。例如兩個實數相乘但結果太大,超出了目前的精度範圍,所以就會向上溢出,變成 inf。還有向下溢出。還有會出現類似 -1 的平方根這種未定義的值,那就是 nan。其實浮點數裡面有非常多的細節,在 IEEE 754 中都有定義,包括四種 rounding 規則等,目的都是盡量不丟失精度,有一致性的表達,照顧到所有情況。

整數有清晰明確的範圍,使用整數一般都是有前提條件的。並且許多程序演算法甚至會依賴整數的溢出結果(迴繞之後的值)。整數的表達和計算相對於浮點數來說更簡單,並且還能提供位運算和求余運算。


謝邀

。浮點數是有一定的精度的。

.#INF:這個值表示「無窮大inf (infinity 的縮寫)」,即超出了計算機可以表示的浮點數的最大範圍(或者說超過了 double 類型的最大值)。例如,當一個整數除以0時便會得到一個1.#INF/ inf值;相應的,如果一個負整數除以0會得到-1.#INF / -inf 值。


關於浮點數之前的答案已經點明了一條路,就是去查IEEE的規範,因為c等一眾編程語言或直接或間接的都由標準委員會,自然也會採用標準的定義方法(其實你例子中char用的ASCII也是標準哦)這些標準的影響力之大以至於後面的編碼都會盡量保持兼容。(比如utf-8)(但其實說是歷史遺留更貼切)

但其實我不是非常懂題主的思路,因為更令人不好理解的難道不是整數沒有溢出嗎?畢竟很多語言浮點都會溢出,而整數溢出不報錯的卻佔了少數。(比如Java提供了Intenger類來做safe calculation,python,haskell等一眾語言直接上big number)


實名贊成高票回答

哈哈,皮一下皮一下

嘛,我覺得高票說的很好(其實是那個我不知道,學習了學習了),在深入理解計算機系統這本書里,設置NAN是為了表示無意義的數,比如√-1或者∞+∞這種的無法表示的數。

而整數的位數是定死的,並且整數的補碼錶示真的很巧妙,補碼形式並沒有符號位,只是最高位的權值不同罷了,所以補碼參與運算是全部的位數都參與,不像元碼和反碼。這樣精巧的設計肯定會損失一些特徵,那就是無法像浮點數一樣直接用階位和小數位來表示inf,但是這也夠了,對於一些平常的計數,運算整數已經足夠大了。也就是兩個作用不同吧。


說話要說完整……並不是說「浮點數一定是有誤差的」,而是說「用二進位浮點數來表示十進位小數,大部分情況下是會有誤差的」。例如十進位的0.1換算成二進位就是個無限循環浮點數,尾數無限、但是實際存儲時又只能存那麼幾位,自然就有誤差。按你這個表述,十進位也是有誤差的,π就沒法用十進位完美的表示出來,1/3也沒法用十進位完美的表示出來……
推薦閱讀:
相关文章