簡體   English   中英

如何處理浮點計算中的過度精度?

[英]How to deal with excess precision in floating-point computations?

在我的數值模擬中,我的代碼類似於以下代碼段

double x;
do {
  x = /* some computation */;
} while (x <= 0.0);
/* some algorithm that requires x to be (precisely) larger than 0 */

對於某些平台上的某些編譯器(例如gcc)(例如linux,x87 math), x的計算可能高於雙精度(“精度過高”)。 更新 :當我在這里談到精度時,我的意思是精度/和/范圍。)在這些情況下,可以想象,即使下一次x向下舍入到雙倍精度,比較( x <= 0 )也會返回false 0.(並且無法保證x不會在任意時間點向下舍入。)

有沒有辦法進行這種比較

  • 便攜,
  • 適用於內聯的代碼,
  • 沒有性能影響
  • 不排除某些任意范圍(0,eps)?

我嘗試使用( x < std::numeric_limits<double>::denorm_min() )但這在使用SSE2數學時似乎顯着減慢了循環。 (我知道非正規可以減慢計算速度,但我沒想到它們只是移動並比較慢。)

更新:另一種方法是在比較之前使用volatile來強制x進入內存,例如通過寫入

} while (*((volatile double*)&x) <= 0.0);

但是,根據應用程序和編譯器應用的優化,此解決方案也會引入明顯的開銷。

更新:任何容忍的問題在於它是非常隨意的,即它取決於具體的應用程序或上下文。 我更願意在沒有過多精度的情況下進行比較,這樣我就不必做任何額外的假設或在我的庫函數的文檔中引入一些任意的epsilons。

正如Arkadiy在評論中所說,顯式演員((double)x) <= 0.0 應該有效 - 至少根據標准。

C99:TC3,5.2.4.2.2§8:

除了賦值和強制轉換(刪除所有額外的范圍和精度)之外,具有浮動操作數的操作值和受常規算術轉換和浮動常量限制的值將被評估為其范圍和精度可能大於類型。 [...]


如果在x86上使用GCC,則可以使用標志-mpc32-mpc64-mpc80將浮點運算的精度設置為單精度,雙精度和擴展雙精度。

在你的問題中,你說過使用volatile會起作用,但是會有很大的性能損失。 如何在比較期間使用volatile變量,允許x保存在寄存器中?

double x; /* might have excess precision */
volatile double x_dbl; /* guaranteed to be double precision */
do {
  x = /* some computation */;
  x_dbl = x;
} while (x_dbl <= 0.0);

您還應該檢查是否可以通過明確使用long double來加速與最小次正規值的比較並緩存此值,即

const long double dbl_denorm_min = static_cast<long double>(std::numeric_limits<double>::denorm_min());

然后比較

x < dbl_denorm_min

我假設一個體面的編譯器會自動執行此操作,但是人們永遠不會知道......

我想知道你是否有正確的停止標准。 聽起來x <= 0是一個異常條件,但不是終止條件,並且終止條件更容易滿足。 也許在你的while循環中應該有一個break語句,當滿足一些容差時停止迭代。 例如,當兩個連續迭代彼此足夠接近時,許多算法終止。

好吧,GCC有一個標志,-fexcess-precision會導致你正在討論的問題。 它還有一個標志,-ffloat-store,它解決了你正在討論的問題。

“不要將浮點變量存儲在寄存器中。這樣可以避免在機器上出現不必要的過高精度,例如68000浮動寄存器(68881)保持精度高於雙倍應該具有的精度。”

我懷疑該解決方案沒有性能影響,但影響可能不會過於昂貴。 隨機谷歌搜索表明它的成本約為20%。 其實,我不認為這一個解決方案,它是便攜式和對性能沒有影響,因為迫使芯片不使用過多的精度往往要涉及到一些非自由操作。 但是,這可能是您想要的解決方案。

一定要檢查絕對值。 它需要是一個大約零,上下的epsilon。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM