2010-11-12 47 views
1

我們有一個測量數據處理應用程序,目前所有數據保存爲C++ float,這意味着我們的x86/Windows平臺上的32位/ 4位。 (32位Windows應用程序)。x86 4字節浮點數與8字節雙精度浮點數(對比long long)?

由於精度成爲問題,所以有討論轉移到另一種數據類型。目前討論的選項切換到double(8字節)或在__int64(8字節)之上實現固定的十進制類型。

使用__int64爲基本類型的固定小數的解決方案,即使是討論的原因是,有人聲稱double性能(仍然)比處理float小號顯著惡化,我們可能會看到顯著的性能優勢使用原生整數類型存儲我們的號碼。 (請注意,我們真的會很好,固定小數精度,雖然代碼顯然會變得更加複雜。)

顯然我們需要在最後進行基準測試,但是我想問一下,更糟糕的是,看着現代處理器有什麼真相?我猜大數組可能會混淆緩存命中更多的浮動,但否則我真的不明白他們如何可以在性能上有所不同?

+1

「[雙打]混亂的緩存命中更多的漂浮,但否則我真的不明白他們如何可以在性能上有所不同?」呃......是不是計算出更準確的結果,至少是一個可能更費時的任務呢?我從來沒有對這些東西進行過基準測試......我會更加懷疑像日誌或權力這樣更復雜的功能。 – 2010-11-12 09:14:10

+3

爲什麼不寫一個簡單的壓力測試來比較算術運算與浮點數組相比陣列加倍和驗證結果的第一手? – Saul 2010-11-12 09:16:02

回答

5

這取決於你做什麼。在當前的x86和POWER架構處理器上,double上的加法,減法和乘法與在float上的加法,減法和乘法一樣快。由於它們的運行時間取決於期望的精確度,所以除法,平方根和超越函數(exp,log,sin,cos等)通常會顯着地慢於雙重參數。

如果你走的是定點,乘法和除法需要用長整數乘/除指令來實現,這些指令通常比在doubles上的算術要慢(因爲處理器沒有爲其優化太多)。更何況,如果你在32位模式下運行,需要從幾個32位長的乘法合成一個長64位乘以128位結果!

緩存利用率在這裏是一個紅色的鯡魚。 64位整數和雙精度是相同的大小 - 如果你需要32位以上的數據,無論如何你都會接受懲罰。

+0

感謝您指出我們無論如何都需要64位 - 至少緩存參數現在不在窗口中! – 2010-11-12 12:14:09

0

使用各種SIMD指令集,您可以以與單一成本相同的成本執行4個單精度浮點運算,本質上,您可以將4個浮點數打包到一個128位寄存器中。當切換到雙打時,您只能將2個雙打裝入這些寄存器,因此您只能同時進行兩個操作。

+0

只要您的代碼不是自動矢量化的(我從來沒有在任何不完全無關的循環中看到這樣的工作),或者使用內在函數,它使用標量SSE或x87浮點運算。它們都只將一個值打包到一個寄存器中,所以較低的SIMD寬度並不重要。 – 2010-11-12 09:30:28

2

實現64個固定點並不是很有趣。特別是對於更復雜的功能,如Sqrt或對數。對於簡單操作(如添加),整數可能會更快一些。你需要處理整數溢出。在實施四捨五入時你需要小心,否則錯誤很容易積累。

我們在C#項目中實現了固定點,因爲我們需要確定性,即.net上的浮點不能保證。這是相當痛苦的。一些公式包含x^3 bang int溢出。除非你有真正令人信服的理由不使用浮點數或雙精度數來代替定點數。

來自SSE2的SIMD指令進一步使比較複雜化,因爲它們允許同時對多個浮點數(4個浮點數或2個雙精度數)進行操作。我會使用兩倍,並嘗試利用這些說明。所以double可能會比float更慢,但與int整合比較困難,我更喜歡float/double over fixedpoint是大多數場景。

1

總是最好測量而不是猜測。是的,在許多體系結構中,double的計算處理數據是兩次數據,因爲計算結果爲float(並且long doubles仍然較慢)。然而,正如其他答案和對這個答案的評論所指出的那樣,x86架構並不遵循與ARM處理器,SPARC處理器等相同的規則。在x86 float s,double s和long double s都是轉換爲long double s進行計算。我應該知道這一點,因爲轉換導致x86結果比SPARC更準確,並且Sun經歷了很多麻煩以獲得對Java不太準確的結果,sparking some debate(請注意,該頁面是從1998年開始的,此後發生了變化) 。

此外,doubles上的計算內置於CPU中,其中將使用軟件寫入固定十進制數據類型的計算並可能較慢。

你應該能夠找到一個體面的固定大小的小數庫並進行比較。

+2

至少在x86上,基本浮點運算(加/減/乘)總是以大於80位('長雙精度)的精度執行,然後四捨五入到當前指定的精度。大多數基本指令在'float','double'和'long double'上都有相同的時間(注意大多數Windows編譯器都有'double double' =='double' - 他們永遠不會使用80位浮點數)。 – 2010-11-12 09:27:08

+2

@Fabian Giesen,實際上,如果啓用SSE2,浮動計算不再使用x87硬件完成。 – avakar 2010-11-12 09:47:49

+0

它們不再使用x87 *指令*,但是它是相同的硬件,它執行SSE2和x87代碼,並且加法器/乘法器仍然支持全寬操作,無需額外的成本,即使結果不是'寫回寄存器。 – 2010-11-12 10:08:37

3

我很難理解的理由是,「比float慢兩倍,我們將使用64位int」。猜測性能一直是需要大量經驗的黑色藝術,在今天的硬件上,考慮到要考慮的因素數量,情況更糟糕。即使測量也很困難。我知道幾種情況,其中微型基準借給了一種解決方案,但在上下文測量中表明另一種更好。

首先注意到,已經給出的兩個因素解釋了比float更慢的雙重性能,這兩個因素並不相關:所需帶寬與雙64位int相同,而SSE2矢量化將帶來優勢雙...

然後考慮比使用整數計算將增加整數寄存器和計算單位的壓力,當浮動點顯然將保持不變。 (我已經看到了以double爲單位進行整數計算的情況,因爲增加了計算單位而獲勝)

所以我懷疑滾動你自己的定點算法會比使用double更有優勢(但我可以顯示錯誤的措施)。

4

查找它。兩家公司和英特爾公司都在其網站上免費提供的PDF文檔中公佈CPU的指令延遲。

然而,大部分,性能不會有顯著不同,或有兩個原因:

使用的x87 FPU,而不是SSE時
  • ,所有浮點操作都在80計算位內部精度,然後四捨五入,這意味着實際計算對於所有浮點類型同樣昂貴。然後唯一的代價是與內存相關的(就CPU高速緩存和內存帶寬使用而言,這只是floatdouble之間的一個問題,但如果與int64比較則無關緊要)
  • 有或沒​​有SSE,幾乎所有浮點操作是流水線操作。當使用SSE時,double指令可能(我沒有看過這個)比它們的float等價物具有更高的等待時間,但吞吐量是相同的,因此應該可以用doubles實現類似的性能。

這也不是一個固定點數據類型實際上會更快。它可能,但在某些操作之後保持此數據類型一致的開銷可能會超過節省。現代CPU上的浮點操作相當便宜。他們有一點延遲,但如前所述,他們通常是流水線,可能隱藏這個成本。

所以我的建議是:

  1. 寫一些快速測試。編寫執行大量浮點運算的程序應該不會那麼困難,然後測量double版本相對於float版本的運行速度要慢多少。
  2. 看它的說明書,看看自己是否有floatdouble計算
0

正如許多人所說之間的任何顯著的性能差異,64位INT可能是不值得的,如果雙是一種選擇。至少在SSE可用時。這可能會在各種微控制器上有所不同,但我想這不是你的應用程序。如果你需要更多精確的浮點數,你應該記住this operation is sometimes problematic浮點數和雙精度,並且對整數更精確。