2017-06-18 126 views
2

使用浮點數相減的方式,舍入不起作用。即使使用浮點數相減的圓形連接

IEEE754-2008,4.3.1說「roundTiesToEven ......如果包圍不可表示無限精確的結果,兩個最接近的浮點數同樣臨近,一個以偶數至少顯著位須交付」

英特爾文檔說,這是默認模式,更明確地定義它:

https://software.intel.com/en-us/node/503710

我會先通過浮點加法走 - 來驗證我的假設 - 因爲我希望它的工作原理。然後,我會稍微修改我的測試案例,以顯示我的理解失敗的地方。

讓我們兩個單浮點數,這裏代表了「binary32」格式:

S Exponent  Significand 
0 10000010 00000000000000000000001 (0x41000001) 
    130 

0 01111111 00000000000000000000100 (0x3F800004) 
    127 

添加它們,我轉向具有較小指數(第二個操作數)數的尾數向右3處(我還添加隱含的領先的1這裏):兩個(100)之間

1.00000000000000000000001 
+ 0.00100000000000000000000 100 
---------------------------- 
    1.00100000000000000000001 

由於移出值中旬的方式,它應該輪總和爲偶數值:

1.00100000000000000000010 

在二進制中,全部價值是:

0 10000010 00100000000000000000010 (0x41100002) 

我可以驗證這一點:

#include <stdint.h> 
#include <stdio.h> 

union uval { 
    float fval; 
    int32_t ival; 
}; 

int main() 
{ 
    union uval a, b, c; 
    a.ival = 0x41000001; 
    b.ival = 0x3F800004; 
    c.fval = a.fval + b.fval; 
    printf("%08x\n", c.ival); 
} 

打印:

./a.out 
41100002 

如果我添加一個到第一個操作數:

a.ival = 0x41000002; 

我得到同樣的東西。它圓潤到甚至造成:

./a.out 
41100002 

到目前爲止,一切都很好。但是,如果我用的是原始值和修改的第二個參數通過符號位設置爲1是負數:

a.ival = 0x41000001; 
b.ival = 0xBF800004; 

我得到:

./a.out 
40E00001 

那就是:

0 10000001 11000000000000000000001 
    129 

第二個參數對齊後,結果應該仍然在兩個值之間。在這種情況下,爲什麼沒有達到平衡的價值呢?

+1

爲什麼你期望最終的結果是介於兩者之間的一半,而不是完全可以代表的? –

+0

由於我在對齊時將數字「100」移出第二個操作數(源操作數的指數相差3)。 – JeffB

+2

你有沒有想過在重要意義上發生的事情,結果變化的指數? –

回答

5

爲了理解最終結果,重要的是要記住四捨五入是IEEE 754算法的最後一步。它通過規範化完成,然後四捨五入。

查看兩個計算的高有效結尾,兩個操作數在顯式位中都有零。在b隱含一位右移相匹配的指數三個地方:

1.000 
0.001 

添加這些給出1.001,所以指數保持相同a,並且在結果明確一位。

減去它們給出0.111。標準化將此左移一位,以擺脫前導0,給出1.110。兩個明確的一位存儲在結果中。

現在看低意義的結局。原始減法將在「中間位置」位置留下一位。由歸一化引起的左移將其轉化爲最不重要的存儲位,並且結果是確切的。