我最近看到了一个很好的解决编程问题的方法。给定2个列表,请在列表之一中找到缺失的数字。
我最初的解决方案是这样的:
long long missing_2(long long a[], long long b[], long long bsize) {
long long asum = a[bsize], bsum = 0;
for (long long i = 0; i < bsize; i++) {
asum += a[i];
bsum += b[i];
}
return asum-bsum;
}
但是有人建议这样:
long long missing_3(long long a[], long long b[], long long bsize) {
long long sum = 0 ^ a[bsize];
for (long long i = 0; i < bsize; i++) {
sum ^= a[i];
sum ^= b[i];
}
return sum;
}
出于好奇,我给这两个解决方案定了时间,以为第二个解决方案missing_3
会更快。我得到了这些结果
missing_2:耗时:16.21s
missing_3:耗时:23.39s
使用for循环生成列表。列表b用整数0-1000000000
填充,列表a用1-1000000000填充,末尾附加一个随机数(因此它包含1个不同的(额外)值。
问题 按位版本需要23.39s,求和版本需要16.21s。知道为什么按位版本会比求和版本慢得多吗?我本以为按位运算比加法或至少类似运算要快。
编辑:
使用g++
编译,没有额外的标志/选项。
Edit2:
经过标记-O1
和-O2
的测试,没有明显区别。
Edit3:
以下是驱动程序代码:
long long smaller_size = 1000000000;
long long* a = new long long[smaller_size+1];
long long* b = new long long[smaller_size];
for(long long i = 0; i < smaller_size; i++){
a[i] = b[i] = i;
}
a[smaller_size] = 1434;
// std::cout << missing_1(a, b, smaller_size) << std::endl;
clock_t tStart = clock();
std::cout << "Start List Test\n";
std::cout << missing_2(a, b, smaller_size) << std::endl;
printf("Time taken: %.2fs\n", (double)(clock() - tStart)/CLOCKS_PER_SEC);
tStart = clock();
std::cout << missing_3(a, b, smaller_size) << std::endl;
printf("Time taken: %.2fs\n", (double)(clock() - tStart)/CLOCKS_PER_SEC);
编辑5:“计时”部分已更新(无时间更改)
clock_t tStart = clock();
std::cout << "Start List Test\n";
double time;
missing_2(a, b, smaller_size);
time = (double)(clock() - tStart)/CLOCKS_PER_SEC;
printf("Time taken: %.2fs\n", time);
tStart = clock();
missing_3(a, b, smaller_size);
time = (double)(clock() - tStart)/CLOCKS_PER_SEC;
printf("Time taken: %.2fs\n", time);
答案 0 :(得分:2)
正如Peter和Matteo在问题评论中提到的那样。
尽管对于单个操作与加法,异或将相等/更快。由于pipelining,XOR版本比求和版本慢。
一个XOR必须等待上一个XOR操作完成才能开始其操作,而求和(加法)可以并行运行并因此利用流水线。反过来,允许求和的结果比按位XOR更快。
这个答案是受到彼得斯评论的启发。我只是想确保问题有一个可用的答案,而Peter选择不回答。
编辑:
感谢phuclv,将代码分别更改为求和数组a
和b
(请参见下面的注释)会破坏依赖关系,并导致XOR返回的结果比Summation更快/相等。