[英]Why are size_t and unsigned int slower than int?
我正在使用下面的簡單交換排序算法在Windows中的Visual Studio項目中嘗試不同的整數類型。 處理器是英特爾。 代碼是在Release x64中編譯的。 優化設置為“最大化速度(/ O2)”。 與編譯設置對應的命令行是
/permissive- /GS /GL /W3 /Gy /Zc:wchar_t /Zi /Gm- /O2 /sdl /Fd"x64\Release\vc141.pdb" /Zc:inline /fp:precise /D "NDEBUG" /D "_CONSOLE" /D "_UNICODE" /D "UNICODE" /errorReport:prompt /WX- /Zc:forScope /Gd /Oi /MD /Fa"x64\Release\" /EHsc /nologo /Fo"x64\Release\" /Fp"x64\Release\SpeedTestForIntegerTypes.pch" /diagnostics:classic
代碼本身:
#include <ctime>
#include <vector>
#include <iostream>
void sort(int N, int A[], int WorkArray[]) // exchange sort
{
int i, j, index, val_min;
for (j = 0; j < N; j++)
{
val_min = 500000;
for (i = j; i < N; i++)
{
if (A[i] < val_min)
{
val_min = A[i];
index = i;
}
}
WorkArray[j] = A[j];
A[j] = val_min;
A[index] = WorkArray[j];
}
}
int main()
{
std::vector<int> A(400000), WorkArray(400000);
for(size_t k = 0; k < 400000; k++)
A[k] = 400000 - (k+1);
clock_t begin = clock();
sort(400000, &A[0], &WorkArray[0]);
clock_t end = clock();
double sortTime = double(end - begin) / CLOCKS_PER_SEC;
std::cout << "Sort time: " << sortTime << std::endl;
return 0;
}
WorkArray
只需要在排序之前保存向量。 關鍵是,這次排序花了我22.3秒才完成。 有趣的是,如果我將類型int
更改為size_t
用於數組A
, WorkArray
(在std::vector
和函數sort
的參數列表中),以及val_min
,則時間增加到67.4! 這慢了三倍 ! 新代碼如下:
#include <ctime>
#include <vector>
#include <iostream>
void sort(int N, size_t A[], size_t WorkArray[]) // exchange sort
{
int i, j, index;
size_t val_min;
for (j = 0; j < N; j++)
{
val_min = 500000U;
for (i = j; i < N; i++)
{
if (A[i] < val_min)
{
val_min = A[i];
index = i;
}
}
WorkArray[j] = A[j];
A[j] = val_min;
A[index] = WorkArray[j];
}
}
int main()
{
std::vector<size_t> A(400000), WorkArray(400000);
for(size_t k = 0; k < 400000; k++)
A[k] = 400000 - (k+1);
clock_t begin = clock();
sort(400000, &A[0], &WorkArray[0]);
clock_t end = clock();
double sortTime = double(end - begin) / CLOCKS_PER_SEC;
std::cout << "Sort time: " << sortTime << std::endl;
return 0;
}
請注意,我仍然為函數局部變量i
, j
, index
, N
保留類型int
,因此在這兩種情況下, i++
和j++
僅有的兩個算術運算應該花費相同的時間。 因此,這種放緩與其他原因有關。 它與內存對齊問題或寄存器大小或其他內容有關嗎?
但最令人發指的部分是當我將int
更改為unsigned int
。 unsigned int
和int
占用相同的字節數,即4( sizeof
顯示)。 但是unsigned int
的運行時間是65.8秒! 雖然第一個結果有點可以接受,但第二個結果讓我很困惑! 為什么運行這樣一個甚至不涉及符號檢查的簡單算法所需的時間差別如此之大?
感謝所有人都解決了這兩個問題。 我在哪里可以開始閱讀有關這些硬件級優化特性的更多信息? 我不關心排序算法本身,它僅用於說明問題。
更新:再一次,我強調在所有三種情況下我都使用int作為數組索引 。
檢查生成的程序集中的所有3個變量( int
, unsigned
, size_t
),最大的區別是在int
情況下, sort
函數中的循環被展開並使用SSE指令(一次處理8個int),而在其他兩個案例都沒有。 有趣的是,在int
情況下調用sort
函數,而在另外兩個函數中將其內聯到main
中(可能是由於循環展開導致函數的大小增加)。
我正在使用cl /nologo /W4 /MD /EHsc /Zi /Ox
從命令行編譯,使用dumpbin
來獲取反匯編,使用工具集Microsoft (R) C/C++ Optimizing Compiler Version 19.12.25830.2 for x64
。
對於int
,我的執行時間約為30秒,而其他兩個執行時間為100秒。
我在VS2017中嘗試了這段代碼。 我成功地復制了。
我按如下方式修改了代碼,以便時間幾乎相同。
原因似乎是由於隱式轉換數組索引。
#include <ctime>
#include <vector>
#include <iostream>
using namespace std;
// exchange sort
template<typename elem_t, typename index_t>
void sort(index_t size, elem_t* a, elem_t* b)
{
index_t index = 0, i, j;
elem_t min;
for (j = 0; j < size; j++)
{
min = 500000;
for (i = j; i < size; i++)
{
if (a[i] < min)
{
min = a[i];
index = i;
}
}
b[j] = a[j];
a[j] = min;
a[index] = b[j];
}
}
template<typename elem_t, typename index_t, index_t size>
void test() {
//vector<elem_t> a(size);
//vector<elem_t> b(size);
elem_t a[size];
elem_t b[size];
for (index_t k = 0; k < size; k++)
a[k] = (elem_t)(size - (k + 1));
clock_t begin = clock();
sort(size, &a[0], &b[0]);
clock_t end = clock();
double sortTime = double(end - begin) / CLOCKS_PER_SEC;
cout << "Sort time: " << sortTime << endl;
}
int main()
{
const int size = 40000;
cout << "<size_t, int>" << endl;
test<size_t, int, size>();
cout << endl;
cout << "<size_t, size_t>" << endl;
test<size_t, size_t, size>();
cout << endl;
cout << "<int, int>" << endl;
test<int, int, size>();
cout << endl;
cout << "<int, size_t>" << endl;
test<int, size_t, size>();
cout << endl;
cout << "<uint, int>" << endl;
test<unsigned int, int, size>();
cout << endl;
cout << "<uint, size_t>" << endl;
test<unsigned int, size_t, size>();
cout << endl;
cout << "<uint, uint>" << endl;
test<unsigned int, unsigned int, size>();
cout << endl;
}
就個人而言,我不喜歡隱式演員。 要解決此類問題,請將警告級別提高到最大值,並解決所有警告,然后轉換為通用代碼。 這有助於您確定問題所在。
此代碼的結果顯示為各種組合的結果。
signed vs unsigned: 在C中,為什么“signed int”比“unsigned int”更快?
類型大小(int32 vs int64)
數組索引匯編代碼
vc ++優化:/ O2(最大優化(偏好速度))
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.