2010-04-07 26 views
4

編輯:我在調試會議期間犯了一個錯誤,導致我問這個問題。我看到的差異實際上是在打印雙精度和解析雙精度(strtod)。斯蒂芬的回答在整頓之後仍然很好地回答了我的問題,所以我想我會留下這個問題,以防其他人有用。在打印,轉換中考慮FPU舍入模式的編譯平臺

一些(最多)C彙編平臺我訪問不採取FPU舍入模式考慮在內時

  • 64位整數轉換成double;
  • 印刷double

這裏沒什麼特別的:Mac OS X Leopard,各種最新的Linux和BSD變種,Windows。

另一方面,Mac OS X Snow Leopard在做這兩件事情時似乎將舍入模式考慮在內。當然,擁有不同的行爲讓我無法終結。

下面是兩種情況的典型片段:

#if defined(__OpenBSD__) || defined(__NetBSD__) 
# include <ieeefp.h> 
# define FE_UPWARD FP_RP 
# define fesetround(RM) fpsetround(RM) 
#else 
# include <fenv.h> 
#endif 

#include <float.h> 
#include <math.h> 

fesetround(FE_UPWARD); 

... 
double f; 
long long b = 2000000001; 
b = b*b; 
f = b; 

... 
printf("%f\n", 0.1); 

我的問題是:

  1. 是不是有什麼不醜,我可以做標準化在所有平臺上的行爲?一些隱藏的設置可以告訴那些採用舍入模式的平臺,而不是反過來?
  2. 是行爲標準之一嗎?
  3. 當不使用FPU舍入模式時,我可能會遇到什麼?向零回合?回合到最近?請告訴我,只有一個替代:)

關於2.我發現在標準的地方,它說,浮動轉換爲整數總是截斷(舍入爲零),但我不能找到整數 - >浮動方向的任何東西。

回答

4

如果您尚未設置舍入模式,它應該是IEEE-754默認模式,該模式是舍入到最近的。

對於從整數轉換到浮動,C標準說(§6.3.1.4):

當整數類型的值是 轉換成實浮動型,如果 值被轉換可以在 中表示爲 ,但是沒有變化。 轉換如果該值是 是在可以表示的值 的範圍內,但不能被 精確表示,其結果是 或者最近的更高或最近 下可表示值,在 實現定義的方式選擇的。如果 正在轉換的值在 之外,則值的範圍可以是 表示的行爲是 未定義。

所以這兩種行爲都符合C標準。

C標準規定(§F.5)IEC60559浮點格式和字符序列之間的轉換按照IEEE-754標準正確舍入。對於非IEC60559格式,建議使用這種格式,但不是必需的。 1985年IEEE-754標準說(條款5.4):

換算應如在 表3.否則指定第4操作數 位於的範圍內指定,四捨五入到最接近的 進行正確舍入 ,在轉換 結果誤差不得超過 0.47單位在目的地的至少顯著位數超過由所述舍入 規格第4節的發生 誤差,提供 該李氏指數溢出/下溢不 發生。在定向舍入模式 中,錯誤應具有正確的符號 ,並且在 最後位置不得超過1.47個單位。

第(4)部分實際上說的是,操作應根據當前的舍入模式進行。即如果你改變舍入模式,IEEE-754說float-> string轉換的結果應該相應地改變。整數 - >浮點轉換同上。

2008年修訂版的IEEE-754標準的表示(第4.3條):

四捨五入的方向屬性 影響所有的計算操作 可能是不準確的。不明確的數字 浮點結果始終與未被佔用的結果具有相同的符號 。

這兩種轉換都被定義爲第5節中的計算操作,所以它們也應該按照主要的舍入模式來執行。

我認爲Snow Leopard在這裏有正確的行爲(假設它是正確根據主要舍入模式將結果四捨五入)。如果你想強制執行舊的行爲,我想你總是可以將你的printf調用包裝成修改舍入模式的代碼,儘管這顯然不理想。

或者,您可以在C99兼容平臺上使用%a格式說明符(十六進制浮點數)。由於這種轉換的結果總是精確的,所以它將永遠不會受到主要舍入模式的影響。我不認爲Windows C庫支持%a,但如果你需要它,你可以很輕鬆地移植BSD或glibc實現。

+0

感謝您的詳盡答覆。對於整數 - >雙重轉換,我將嘗試用'f =(double)(b&0x00000000FFFFFFFF)+(double)(b&0xFFFFFFFF00000000);'來代替'f = b;';',這應該在所有地方給出相同的行爲 - 每個轉換是準確的,舍入決定是由雙+做出的,並且應該總是按照主要的舍入模式。 – 2010-04-07 23:04:16

+0

@Pascal:是的,它應該可以工作(實際上在某些平臺上如何實現int64 - > double轉換)。但是,我也發現,Intel有*兩組舍入控制位(x87和SSE)。我知道雪豹上的'fesetround'設置了它們兩個;是否有可能無法在其他平臺上設置兩個控制字,並且某些轉換是使用未設置控制字的單元完成的?可能值得研究這種可能性。 – 2010-04-07 23:08:25