[英]Why is dividing slower than bitshifting in C++?
我编写了两段代码,一段将随机数除以二,另一段将同一随机数右移一次。 据我了解,这应该产生相同的结果。 但是,当我同时处理这两段代码时,我始终会得到数据,说明移位速度更快。 这是为什么?
移位代码:
double iterations = atoi(argv[1]) * 1000;
int result = 0;
cout << "Doing " << iterations << " iterations." << endl;
srand(31459);
for(int i=0;i<iterations;i++){
if(i % 2 == 0){
result = result + (rand()>>1);
}else{
result = result - (rand()>>1);
}
}
划分代码:
double iterations = atoi(argv[1]) * 1000;
int result = 0;
cout << "Doing " << iterations << " iterations." << endl;
srand(31459);
for(int i=0;i<iterations;i++){
if(i % 2 == 0){
result = result + (rand() / 2);
}else{
result = result - (rand() / 2);
}
}
时间和结果:
$ time ./divide 1000000; time ./shift 1000000
Doing 1e+09 iterations.
real 0m12.291s
user 0m12.260s
sys 0m0.021s
Doing 1e+09 iterations.
real 0m12.091s
user 0m12.056s
sys 0m0.019s
$ time ./shift 1000000; time ./divide 1000000
Doing 1e+09 iterations.
real 0m12.083s
user 0m12.028s
sys 0m0.035s
Doing 1e+09 iterations.
real 0m12.198s
user 0m12.158s
sys 0m0.028s
附加信息:
不是; 在您正在运行的架构上速度较慢。 它几乎总是比较慢,因为移位后的硬件微不足道,而除法则是一场噩梦。 在基础10中,对您来说更简单的是78358582354 >> 3或78358582354/85? 不管输入如何,指令通常花费相同的时间执行,在您这种情况下,将/2
转换为>>1
是编译器的工作。 CPU只是按照提示执行。
它实际上并不慢。 我已经使用nonius运行您的基准测试, 如下所示:
#define NONIUS_RUNNER
#include "Nonius.h++"
#include <type_traits>
#include <random>
#include <vector>
NONIUS_BENCHMARK("Divide", [](nonius::chronometer meter)
{
std::random_device rd;
std::uniform_int_distribution<int> dist(0, 9);
std::vector<int> storage(meter.runs());
meter.measure([&](int i) { storage[i] = storage[i] % 2 == 0 ? storage[i] - (dist(rd) >> 1) : storage[i] + (dist(rd) >> 1); });
})
NONIUS_BENCHMARK("std::string destruction", [](nonius::chronometer meter)
{
std::random_device rd;
std::uniform_int_distribution<int> dist(0, 9);
std::vector<int> storage(meter.runs());
meter.measure([&](int i) { storage[i] = storage[i] % 2 == 0 ? storage[i] - (dist(rd) / 2) : storage[i] + (dist(rd) / 2); });
})
这些是结果:
如您所见,它们都是并驾齐驱的。
(您可以在此处找到html输出)
PS:看来我忘了重命名第二项考试。 我的错。
结果的差异似乎正在波及结果之间,因此您无法真正分辨出结果是否不同。 但一般来说,单次操作无法完成除法,而移位可以,因此通常移位速度应该更快。
但是,因为您的代码中有文字2,所以我猜想即使没有优化,编译器也会生成相同的代码。
请注意, rand返回int
并将int
(默认情况下为有符号)除以2与按1移位是不同的。您可以轻松地检查生成的asm并查看差异,也可以简单地检查生成的二进制大小:
> g++ -O3 boo.cpp -c -o boo # divide
> g++ -O3 foo.cpp -c -o foo # shift
> ls -la foo boo
... 4016 ... boo # divide
... 3984 ... foo # shift
现在添加static_cast
补丁:
if (i % 2 == 0) {
result = result + (static_cast<unsigned>(rand())/2);
}
else {
result = result - (static_cast<unsigned>(rand())/2);
}
并再次检查大小:
> g++ -O3 boo.cpp -c -o boo # divide
> g++ -O3 foo.cpp -c -o foo # shift
> ls -la foo boo
... 3984 ... boo # divide
... 3984 ... foo # shift
确保您可以验证两个二进制文件中生成的asm相同
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.