这里为什么/如何划分和乘法同样快?

时间:2018-04-20 10:36:24

标签: c++ performance floating-point

我正在尝试制作一个简单的基准算法,以比较不同的操作。在我进入实际功能之前,我想检查一个具有详细记录结果的小案例:乘法与除法。

分部应该从我读过的文献中大幅度减少。当我编译并运行算法时,时间大约为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;
}

1 个答案:

答案 0 :(得分:4)

您不只是测量乘法/除法的速度。如果您将代码放入enter image description here,则可以看到生成的程序集。

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