为什么/如何在这里除法和乘法同样快?

Why/how are division and multiplication equally fast here?

本文关键字:在这里 除法 为什么      更新时间:2023-10-16

我正在尝试制作一个简单的基准测试算法,以比较不同的操作。在我继续实际函数之前,我想检查一个有据可查的结果的琐碎情况:乘法与除法。

从我读过的文献来看,分裂应该会损失得相当远。当我编译并运行算法时,时间大约为 0。我添加了一个打印的累加器,以确保实际执行并重试操作。然后我改变了循环,数字,洗牌等等。所有这些都是为了防止任何可能导致"除法"的事情做浮点除法以外的任何事情。无济于事。时代还是基本相等的。

在这一点上,我看不出它能从浮点分界线中走出来,我放弃了。它赢了。但我真的很好奇为什么时间如此接近,我错过了哪些警告/错误,以及如何修复它们。

(我知道用随机数据填充向量然后洗牌是多余的,但我想确保数据被访问,而不仅仅是在循环之前初始化。

(我知道"字符串比较是邪恶的"。如果这是平等时代的原因,我很乐意加入猎巫。如果没有,请不要提及。

编译:

g++ -std=c++14 main.cc 

测试:

./a.out multiply
2.42202e+09
1000000
t1 = 1.52422e+09    t2 = 1.52422e+09
difference = 0.218529
Average length of function : 2.18529e-07 seconds 
./a.out divide
2.56147e+06
1000000
t1 = 1.52422e+09    t2 = 1.52422e+09
difference = 0.242061
Average length of function : 2.42061e-07 seconds 

代码 :

#include <iostream>
#include <string>
#include <vector>
#include <algorithm>    
#include <random>
#include <sys/time.h>
#include <sys/resource.h>
double get_time()
{
struct timeval t;
struct timezone tzp;
gettimeofday(&t, &tzp);
return t.tv_sec + t.tv_usec*1e-6;
}
double multiply(double lhs, double rhs){
return lhs * rhs;
}

double divide(double lhs, double rhs){
return lhs / rhs;
}

int main(int argc, char *argv[]){
if (argc == 1)
return 0;
double grounder = 0; //prevent optimizations
std::default_random_engine generator;
std::uniform_real_distribution<double> distribution(1.0, 100.0);
size_t loop1 = argc > 2 ? std::stoi (argv[2]) : 1000;
size_t loop2 = argc > 3 ? std::stoi (argv[3]) : 1000;
std::vector<size_t>vecL1(loop1);
std::generate(vecL1.begin(), vecL1.end(), [generator, distribution] () mutable { return distribution(generator); });
std::vector<size_t>vecL2(loop2);
std::generate(vecL2.begin(), vecL2.end(), [generator, distribution] () mutable { return distribution(generator); });
double (*fp)(double, double);
std::string function(argv[1]);
if (function == "multiply")
fp = (*multiply);
if (function == "divide")
fp = (*divide);
std::random_shuffle(vecL1.begin(), vecL1.end());
std::random_shuffle(vecL2.begin(), vecL2.end());
double t1 = get_time();
for (auto outer = vecL1.begin(); outer != vecL1.end(); outer++)
for (auto inner = vecL2.begin(); inner != vecL2.end(); inner++)
grounder += (*fp)(*inner, *outer);
double t2 = get_time();
std::cout << grounder << 'n';
std::cout << (loop1 * loop2) << 'n';
std::cout << "t1 = " << t1 << "tt2 = " << t2 
<< "ndifference = " << (t2 - t1) << 'n';
std::cout << "Average length of function : " << (t2 - t1) * 1/(loop1 * loop2) << " seconds n";
return 0;
}

你不只是在测量乘法/除法的速度。如果将代码放入 https://godbolt.org/则可以看到生成的程序集。

您正在测量调用函数的速度,然后在函数内执行乘法/除法。与函数调用的成本相比,单乘/除指令所花费的时间很小,因此会迷失在噪音中。如果你把循环移到函数内部,你可能会看到更多的不同。请注意,通过函数中的循环,编译器可能会决定对代码进行矢量化,这仍然会显示乘法和除法之间是否存在差异,但它不会测量单个 mul/div 指令的差异。