2010-03-04 94 views
5

當我運行完全相同的代碼執行在Windows和Solaris上編譯的完全相同的浮點計算(使用雙精度)時,我得到的結果稍有不同。浮點計算取決於編譯器

我知道由於舍入誤差導致結果不準確。不過,我本來希望四捨五入錯誤是平臺無關的,因此在兩個平臺上給出的結果都是相同的(稍微不正確),但情況並非如此。

這是正常的,還是在我的代碼中有另一個問題?

+2

如果您發佈的代碼的測試用例這將有助於。對於這樣的問題,測試用例不應超過3-4行。 – Sparr 2010-03-04 01:17:35

+1

可能的重複[爲什麼相同的代碼會在32位和64位計算機上產生不同的數值結果?](http://stackoverflow.com/questions/7847274/why-would-the-same-code-yield-different- 32位數字結果與64位數據機) – 2017-01-01 10:41:55

回答

6

在x86上,除非強制爲雙精度,否則通常大多數計算都是以80位數量進行的。我所知道的大多數其他體系結構都是以雙精度進行所有計算(再次,除非被覆蓋)。

我不知道你是在SPARC還是x86上運行Solaris,但如果是前者,那麼我高度懷疑是造成差異的原因。

+1

如果這是Solaris x86,那麼這個80位表示仍然可能是導致差異的原因。 x86上的浮點計算只有在使用(內置)x87數學協處理器時纔會發生80位數量;如果它使用較新的SSE向量單元,則它們是正常的64位雙精度值。 GCC將默認使用x87來與舊處理器兼容;任何其他編譯器都會使用SSE單元,因爲即使對於不是矢量的東西,速度也會更快。 – 2010-03-04 01:42:30

+0

@Brooks:謝謝!非常好的澄清。 – 2010-03-04 01:43:10

+3

不客氣!順便說一下,http://gcc.gnu.org/bugzilla/show_bug.cgi?id=323對此進行了詳盡的討論。 (這也是谷歌首次針對'gcc浮點錯誤'的結果,它會告訴你人們碰到這個問題的頻率!) – 2010-03-04 01:46:42

1

您的問題的主題表明它可能取決於編譯器。它可能,但是你在不同的硬件上運行(假設你的Solaris不是x86的)這一事實表明了這種差異的一個更可能的原因 - 硬件本身的差異。

不同的硬件平臺可能會使用完全不同的硬件設備(FPU,CPU)來執行浮點計算,以獲得不同的結果。此外,通常FPU單元可以通過一些持久性設置進行配置,如無窮大模型,舍入模式等。不同的硬件可能具有不同的默認設置。編譯器通常會生成在程序啓動時初始化FPU的代碼,因爲初始設置也可能不同。最後,C++語言的不同實現可能會以不同的方式實現浮點語義,因此甚至可能會從相同硬件的不同C++編譯器得到不同的結果。

2

我相信在Windows/x86下,您的代碼將以x87精度已經設置爲53位(雙精度)運行,儘管我不確定它的設置時間。在Solaris/x86上,x87 FPU很可能會使用其默認的64位精度(擴展精度),因此也會有所不同。

您可以通過簡單的檢查來檢測正在使用的精度(53位或64位):嘗試計算類似1e16 + 2.9999的值,同時小心避免編譯器常量摺疊優化(例如,定義一個單獨的add函數添加,並關閉可能內聯函數的任何優化)。當使用53位精度(SSE2,或雙精度模式下的x87)時,給出1e16 + 2;當使用64位精度(擴展精度模式下的x87)時,這會產生1e16 + 4.後一個結果來自稱爲「雙舍入」的效應,其中加法結果首先舍入爲64位,然後舍入爲53位。 (直接用Python做這個計算,我在32位Linux上獲得1e16 + 4,而在Windows上獲得1e16 + 2,原因完全一樣。)

這是一篇非常不錯的文章援引戈德堡的「什麼每臺計算機科學家應該知道......」),解釋了一些從使用的x87 FPU所產生的問題:

http://hal.archives-ouvertes.fr/docs/00/28/14/29/PDF/floating-point-article.pdf