Dot-Net

SSE 浮點算術是否可重現?

  • March 1, 2013

x87 FPU 以使用內部 80 位精度模式而著稱,這通常會導致跨編譯器和機器產生意外且不可重現的結果。在我在 .NET 上搜尋可重現的浮點數學時,我發現 .NET 的兩個主要實現(Microsoft 和 Mono)都發出 SSE 指令,而不是 64 位模式下的 x87。

SSE(2) 對 32 位浮點數使用嚴格的 32 位寄存器,對 64 位浮點數使用嚴格的 64 位寄存器。通過設置適當的控製字,可以選擇將非正規數刷新為零。

因此,SSE 似乎不受 x87 精度相關問題的影響,唯一的變數是可以控制的非規範行為。

撇開先驗函式(與 x87 不同,SSE 本身不提供)的問題,使用 SSE 是否能保證跨機器和編譯器的可重現結果?例如,編譯器優化能否轉化為不同的結果?我發現了一些相互矛盾的意見:

如果您擁有 SSE2,請使用它並從此過上幸福的生活。SSE2 支持 32b 和 64b 操作,中間結果是操作數的大小。- Yossi Kreininhttp://www.yosefk.com/blog/consistency-how-to-defeat-the- purpose-of-ieee-floating-point.html

SSE2 指令 (…) 完全符合 IEEE754-1985,它們允許更好的再現性(由於靜態舍入精度)和與其他平台的可移植性。Muller 等人, 浮點算術手冊- p.107

然而:

此外,您不能將 SSE 或 SSE2 用於浮點,因為它的指定太低而無法確定。-約翰·瓦特 http://www.gamedev.net/topic/499435-floating-point-determinism/#entry4259411

SSE 已完全指定*。Muller 是浮點運算方面的專家;你會相信誰,他還是遊戲開發論壇上的某個人?

(*) 對於非 IEEE-754 操作,例如 rsqrtss,實際上有一些例外,英特爾從未完全指定行為,但這不會影響 IEEE-754 基本操作,更重要的是,它們的行為實際上不會改變在這一點上,因為它會破壞太多東西的二進制兼容性,所以它們和指定的一樣好。

正如斯蒂芬所指出的,由給定的 SSE 彙編程式碼產生的結果將是可重現的;您將相同的程式碼輸入相同的輸入,最後得到相同的輸出。(也就是說,約翰·瓦特的話是完全錯誤的。)

但是,您將“編譯器”一詞扔在那裡。那是完全不同的球類游戲。許多編譯器在保持浮點程式碼的正確性方面仍然很糟糕。(ATLAS 勘誤頁提到 clang “無法為某些操作生成正確的程式碼。”)如果您在程式碼中使用特殊函式,那麼在某種程度上,您也受到任何實現您的數學庫的人的擺佈。

引用自:https://stackoverflow.com/questions/15147174