深入理解计算机系统(2.7)------浮点数舍入以及运算
上一篇博客我們講解了二進制小數如何表示以及IEEE浮點標準。而且我們也提到過因為這種表示方法限制了浮點數的范圍和精度,浮點數只能近似的表示一個數。
比如 數字1/5,我們能用十進制小數 0.2 準確的表示,但是我們卻不能把它準確的表示為一個二進制小數,我們只能通過增加二進制表示的長度來提高表示的精度。如下:
那我們該怎么辦呢?
?
1、舍入
對于不能精確的表示的數,我們采取一種系統的方法,找到“最接近”的匹配值,它可以用期望的浮點形式表現出來,這就是舍入。
舍入一共有四種方式,分別是向偶數舍入、向零舍入、向上舍入以及向下舍入。
可以看下面的例子:
?
? 向偶數舍入,是將數字向上或向下舍入,使得結果的最低有效數字是偶數;而向零舍入則是向靠近零的值舍入;向上舍入則是向比它大的方向靠近;向下舍入則是向比它小的方向靠近。
這四個我們可以用一個直角坐標系來理解:
除了向偶數舍入以外,其它三種方式都會有明確的邊界。這里的含義是指這三種方式舍入后的值x'與舍入之前的值x會有一個明確的大小關系,比如對于向上舍入來說,則一定有x <= x'。對于向零舍入來說,則一定有|x| >= |x'|。
那么我們什么時候會使用向偶數舍入呢?
1、比如舍入一組數值,計算這些值的平均數中引入統計偏差,如果向上舍入,那么得到的平均值會比這些數本身的平均值略高;向下舍入,則會偏低。而向偶數舍入則會避免這種偏差,在50%的時間內,它向上舍入,剩下50%的時間內,它向下舍入。
2、在我們不想舍入到整數時,我們只是簡單的考慮最低有效數字是奇數還是偶數。
? 通常情況下我們采取的舍入規則是在原來的值是舍入值的中間值時,采取向偶數舍入,在二進制中,偶數我們認為是末尾為0的數。而倘若不是這種情況的話,則一般會有選擇性的使用向上和向下舍入,但總是會向最接近的值舍入。其實這正是IEEE采取的默認的舍入方式,因為這種舍入方式總是企圖向最近的值的舍入。
?
?2、浮點運算
? 在IEEE標準中,制定了關于浮點數的運算規則,就是我們將把兩個浮點數運算后的精確結果的舍入值,作為我們最終的運算結果。正是因為有了這一個特殊點,就會造成浮點數當中,很多運算不滿足我們平時熟知的一些運算特性。
我們可以先看下面這段程序輸出結果:
| 1 2 3 4 5 6 7 | public void testFloat(){ ????????float f1 = 3.14f + 10000000000f - 10000000000f; ????????float f2 = 3.14f + (10000000000f - 10000000000f); ????????System.out.println(f1); ????????System.out.println(f2); ????????? ????} |
結果都是 3.14 嗎?
我們看到 f1 的值是0,f2的值才是3.14。為什么呢?這是因為前面3.14f+10000000000f ?時,會將 3.14 這個有效數值舍入掉,而導致最終結果為0.0
f2 由于括號的存在,會先進行括號里面的運算,結果是0,然后在與3.14相加。
也就是浮點運算不滿足加法的結合律?a + b + c != a + (b + c)。同時乘法結合律也不滿足:a * b * c != a * (b * c);還要分配律也不滿足:?a * (b + c) != a * b + a * c
浮點數失去了很多運算方面的特性,因此也導致很多優化手段無法進行,比如我們試圖優化下面這樣一段程序。
| 1 2 3 4 5 6 7 | /*?? 優化前?????? */ ????????float x = a + b + c; ????????float y = b + c + d; ????????/* 編譯器試圖省去一個浮點加法????? */ ????????float t = b + c; ????????float x = a + t; ????????float y = t + d; |
上面優化前是進行了四次浮點運算,而編譯器優化后只需要進行三次浮點運算。但是這中間的 x 可能回產生與原始值不同的值,因為它使用了加法運算不同的結合方式。所以現在的編譯器都傾向于保守的方式,避免任何對功能產生的優化,即使是很輕微的影響。
另外,浮點加法滿足單調性屬性:如果 a>=b,那么對于任何a、b以及 x 的值,除了 NaN,都有 x+a >= x+b。無符號或者補碼加法不具有這個實數(和整數)加法的屬性。
?
?3、總結
? 好了,那么到此《深入理解計算機系統》前面兩章的內容我們就結束了,這里我們主要需要了解無符號和補碼編碼格式,以及它們的運算。然后擴展到整數的表示和運算,實數的表示和運算,在實際編程中,我們會經常和數打交道,如何避免一些錯誤,相信看完后會有個大概的了解了。那么接下來我們將學習第三章,這將是一個全新的世界——匯編語言。這肯定比我們前面講的要有趣多了,前面都是和0或者1這樣的數字打交道,后面至少是一種編程語言,相信會更加有趣。
?
轉載于:https://www.cnblogs.com/ghjbk/p/7602919.html
總結
以上是生活随笔為你收集整理的深入理解计算机系统(2.7)------浮点数舍入以及运算的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: PHP去重排序
- 下一篇: 获取url后的指定参数