2017-07-22 34 views
0

我有兩個函數,其中之一是一個帶數組的函數,另一個帶有指針參數。他們返回相同的結果,但我不知道哪一個更好用。數組或指針的Pereferring函數?

#define SIZE 1024 

int sumA(int a[SIZE][SIZE]) 
{ 
    int sum = 0; 
    for(int y = 0; y < SIZE; y++) 
    for(int x = 0; x < SIZE; x++) 
     sum += a[x][y]; 

    return sum; 
} 

int sumB(int *a) 
{ 
    int sum[4] = {0, 0, 0, 0}; 

    for(int i = 0; i < SIZE*SIZE; i += 4) 
    { 
     sum[0] += a[i+0]; 
     sum[1] += a[i+1]; 
     sum[2] += a[i+2]; 
     sum[3] += a[i+3]; 
    } 

    return sum[0] + sum[1] + sum[2] + sum[3]; 
} 
+0

像'魔術數字I + = 4'非常糟糕;如此糟糕,以致它立即使'sumA'成爲更好的選擇。如果您必須使用元素的大小,請使用'sizeof'運算符,而不是硬編碼的數字。 –

+1

爲什麼'sumB'保持4個獨立的總和,只能將它們全部結尾?爲什麼不只有像sumA這樣的總和? –

+1

@Bora U你爲什麼要刪除代碼? –

回答

2

在這兩種情況下,你通過引用傳遞數組,所以沒有區別。

你的求和函數顯然有很多關於傳入的數組的知識。所以我相信最好強制該數組是由函數期望的類型。

編輯:如果您將類型爲int [] []的變量傳遞給接受int指針的函數(int *),則必須將該變量顯式轉換爲int *,否則編譯器將不會接受它。

Therfore

int sumA(int a[SIZE][SIZE]) 

是兩個更好。

1

sumB從性能的角度來看更好,因爲你是loop unrolling。需要注意的是a是4的倍數,你不檢查並可能導致程序崩潰。

編輯:sumA肯定是更好,因爲它是一個很大的嚴格的(它知道確切的尺寸)

+0

沒有任何關係,我懷疑一旦編譯器完成優化'sumB'就會有任何性能優勢。 –

+1

@CareyGregory對coliru(海灣合作委員會)與O3第二個是10倍快 – Sopel

0

第一個解決方案是更類型安全的,但不好的表現:

  1. 循環是爲了隨後通過每個SIZE * sizeof(int)字節增加內存跳轉,這對緩存不利
  2. 您必須依靠編譯器展開循環,甚至意識到它可以通過一個而不是兩個來完成

第二種解決方案是使用分佈式總和變量進行手動循環展開,它與cpu流水線協同工作(如果它不是首先被矢量化的話)並且分支較少。

兩者都得到矢量化,但第二個更好。 在第一個例子中,替換循環順序確實改善了一些事情,但不會使得結果程序集相等(當它們速度接近時,第二個速度會延長几倍)。 https://godbolt.org/g/bW1Jkd 我測量了10倍的性能差異(在帶有gcc的-O3上,使用gcc),贊成第二種解決方案)。

因此,我建議他們兩個人的混合體:

int sumA(int a[SIZE][SIZE]) 
{ 
    static_assert(SIZE % 4 == 0); 
    int* flat_a = &(a[0][0]); 

    int sum[4] = {0, 0, 0, 0}; 

    for(int i = 0; i < SIZE*SIZE; i += 4) 
    { 
     sum[0] += flat_a[i+0]; 
     sum[1] += flat_a[i+1]; 
     sum[2] += flat_a[i+2]; 
     sum[3] += flat_a[i+3]; 
    } 

    return sum[0] + sum[1] + sum[2] + sum[3]; 
} 

這不是一個複雜的功能,一切都還在伊斯利可讀。

另外我不認爲4常數應該做'非魔術',除非展開是完全通用的,這需要一些模板魔術。 命名一個值應該表明它可以在沒有完全破壞所有內容的情況下進行更改。

0

2之間,我會用更多的類型,但與正確的命名sumB可能是可行的,更通用的:int sumSIZESIZEints(const int*)

相反,你期望的sumA一個SIZE被忽略,導致

int sumA(int (*a)[SIZE]) 

更加的類型是:

int sum(const int (&a)[SIZE][SIZE]) 
{ 
    return std::accumulate(&a[0][0], &a[0][0] + SIZE * SIZE, 0); 
}