觉得挺好玩的,很多大神的回答会让人引起很多思考
先看看源程序
#include "stdafx.h"
#include <algorithm>
#include <ctime>
#include <iostream>
int main()
{
// Generate data
const unsigned arraySize = 32768;
int data[arraySize];
for (unsigned c = 0; c < arraySize; ++c)
data[c] = std::rand() % 256;
// !!! With this, the next loop runs faster
std::sort(data, data + arraySize);
// Test
clock_t start = clock();
long long sum = 0;
for (unsigned i = 0; i < 10000; ++i)
{
// Primary loop
for (unsigned c = 0; c < arraySize; ++c)
{
if (data[c] >= 128)
sum += data[c];
}
}
double elapsedTime = static_cast<double>(clock() - start) / CLOCKS_PER_SEC;
std::cout << elapsedTime << std::endl;
std::cout << "sum = " << sum << std::endl;
}
然后,对以上程序分别运行两次,第一次不排序,直接计算,第二次排序,在计算。(就是是否注释掉sort那一行的区别)
在我的电脑上,两次运行的结果分别是
排序后
不排序
通过对比我们发现,排序后的执行时间明显降低了。那么是为什呢?
主要的效率差别在这里
if (data[c] >= 128)
sum += data[c];
对于,底层处理器,每次if判断采用Branch Prediction,分支预测
关于分支预测:http://baike.baidu.com/view/512423.htm?fr=aladdin
对于处理器底层代码,是
分支预测通俗来讲,就是处理器在每次if判断的时候,会根据之前判断的结果进行当前判断的预测,比如之前10次都是true,则先假定当前判断也是true,然后执行。如果发现执行失败,则回退到之前,把本次执行设为false。当数组排序之后,这些假定判断大部分将会成功,也就是说回退的次数会很少。
所以,减少if else是降低分支预测,提高速度的关键
stackflow上给出以下几种解决方式
1、将加法改为位运算,消除分支预测
int t = (data[c] - 128) >> 31;
sum += ~t & data[c];
2、不进行判断
clock_t start = clock();
long long a[] = {0, 0};
long long sum;
for (unsigned i = 0; i < 100000; ++i)
{
// Primary loop
for (unsigned c = 0; c < arraySize; ++c)
{
int j = (data[c] >> 7);
a[j] += data[c];
}
}
double elapsedTime = static_cast<double>(clock() - start) / CLOCKS_PER_SEC;
sum = a[1];
最后,对于这个程序最直接的优化方式
#include "stdafx.h"
#include <algorithm>
#include <ctime>
#include <iostream>
int main()
{
// Generate data
const unsigned arraySize = 32768;
int data[arraySize];
for (unsigned c = 0; c < arraySize; ++c)
data[c] = std::rand() % 256;
// !!! With this, the next loop runs faster
std::sort(data, data + arraySize);
// Test
clock_t start = clock();
long long sum = 0;
// Primary loop
for (unsigned c = 0; c < arraySize; ++c)
{
if (data[c] >= 128)
sum += data[c];
}
sum = sum*10000;
double elapsedTime = static_cast<double>(clock() - start) / CLOCKS_PER_SEC;
std::cout << elapsedTime << std::endl;
std::cout << "sum = " << sum << std::endl;
}
这样,会将执行的效率提高10000倍
执行的时间和结果
附上
建议去看看,因为确实很多思路很好,本文只是分析了部分
原问题连接:http://stackoverflow.com/questions/11227809/why-is-processing-a-sorted-array-faster-than-an-unsorted-array