2013-12-08 38 views
-1

我正在研究大規模仿真的高速計算問題。爲了加速這個過程,我希望做一些優化,其中之一就是在沒有跳轉的情況下僅僅在幾個週期內計算double的絕對值。C上的雙精度操作C

我的想法是,64位雙值由1位符號位,11位指數和52位尾數表示。因此,雙值異或帶着面具: 千萬00000000 00000000 00000000將產生期望的結果:

double abs(double x) { 
    double mask = -0.0e0; 
    return x^mask; 
} 

現在很明顯有幾個原因,一個需要在雙打二進制運算,因此自然編譯器會引發錯誤:

error: invalid operands to binary^(have ‘double’ and ‘double’) 

我想知道是否有什麼辦法可以使在快時尚這個工作,因爲我不希望整個事情轉換成字符數組,並早在別處被提出。這會打破快速計算的目的。

我感謝所有幫助...

+3

So 1 + 8 + 23 = 64.好的,今天我學到了一些新東西。 – 2013-12-08 19:44:30

+2

除此之外,您需要通過具有適當寬度的整數的聯合來輸入「double」;剩下的就留給你作爲練習。 **等等,不。**不要擔心「優化」。你怎麼知道這會比標準庫附帶的股票'abs()'更快?你有基準嗎? (提示:不,它不會,也不會,你沒有。) – 2013-12-08 19:46:02

+0

我同意基準是至關重要的,並且似乎不太可能是股票'abs'的重大改進。但他們將無法對它進行基準測試,直到他們實現它爲止...... –

回答

2

變化對@Artur:
..配套使用大小的整數。
..用double初始化聯合。不是更快,而是更緊。

#include <stdint.h> 
double Abs_double(double d) { 
    union { 
    double d; 
    uint64_t u64; 
    } u = {d}; 
    u.u64 &= ~((uint64_t) 1 << 63); 
    return u.d; 
} 

注:我會留在fabs()除非分析顯示還有其他解決方案快。

+1

我會試一試,並在這裏提供反饋,我需要閱讀工會......謝謝^^ – Iluvatar

+0

好吧,我們在這裏,我做了幾個不同的機器和兩個不同的編譯器測試(icc和gcc),看起來,這個方法比標準庫的abs()平均提高了9.3%。我獲得的最大加速比例大約是12%,因此如果在模擬過程中必須將這個寶寶稱爲幾十億次,它纔會產生影響。 – Iluvatar

+0

非常感謝chux和Artur – Iluvatar

1

還沒有籤,但這應該做的工作:

double abs(double x) 
{ 
    long long tmp = *((long long*)&x); 
    tmp &= ~(1LL << 63); 
    return *((double*)&tmp); 
} 

更新:

用戶評論我的解決辦法是對的上述代碼存在問題。這應該是更好:

double my_abs(double x) 
{ 
    union my64bits 
    { 
     unsigned long long a; 
     double    b; 
    }; 

    union my64bits tmp; 
    tmp.b = x; 
    tmp.a &= ~(1uLL<<63); 

    return tmp.b; 
} 
+0

除了它調用未定義的行爲。 *兩次。* – 2013-12-08 19:49:16

+0

@ H2CO3你的意思是指針走樣的權利? – Artur

+0

準確地說,**和**移入有符號整數的符號位。 (事實上​​,「兩次」應該是「三次」。) – 2013-12-08 19:58:33

-3
double x; 
int *p = (int *)&x; 
*(p+1) ^= (1 << 31); 
+0

這是另一個更糟糕的剽竊副本。 – 2013-12-08 19:56:46

+0

照亮我。像64位雙精度的小端32位系統一樣工作。根據標準,沒有什麼不明確的。 – mb84

+0

你是否看過對其他答案的評論中的談話?在這3條線上有3個地方有未定義的行爲。 – 2013-12-08 20:11:03