【问题标题】:Fastest way to create random vectors for benchmarking为基准测试创建随机向量的最快方法
【发布时间】:2012-11-03 19:14:08
【问题描述】:

所以,我只是在尝试在 C++ 中实现一些排序算法,但我发现目前对它们进行基准测试很烦人,因为不运行算法需要很长时间,而是创建输入数据。我目前测试每个输入长度(1000、2000,...)10 次,以获得稍微平均的时间。对于这 10 次中的每一次,我都会创建一个长度正确的新随机 vector,方法是:

    // Each of the 10 times.
    for(int j = 0; j < 10; j++) {

        A.clear();

        // 'i' is the current input size.
        for(int k = 0; k < i; k++) {
            A.push_back(rand() % 10000);
        }

        // Other stuff
    }

有没有更好的方法来做到这一点?我应该费心将 rand() 限制在 10000,还是只是我的强迫症大脑喜欢整数? (即,当您认为模运算实际上执行到 - 目前 - 10 的每个循环 10,000 时,该模运算实际上是否会花费大量时间。)或者,我是否真的应该在每次运行时创建一个新向量种类?我一直这样做是因为我觉得创建的向量可能会存在偏差,因此如果生成该向量然后使用 10 次,那么答案可能会大错特错......

【问题讨论】:

  • 与随机数生成相比,我无法想象模数是相关的。但是,很容易测试:只需将其移除并测量。 (你会测试发布版本,不是吗?)
  • 排序算法真的像随机数据。您没有创建准确的基准,请使用真实数据。
  • @Hans Passant 你能举例说明我在哪里可以找到一些不错的预制真实数据吗?因为我担心在考虑如何生成真实数据时我不知道从哪里开始......尤其是当我试图想象有多少不同的类型时(非常预先排序,非常混乱,等),这会更常见......
  • 如果你想真正彻底,std::next_permutation() 是你的朋友。 :)

标签: c++ benchmarking stdvector


【解决方案1】:

有没有更好的方法来做到这一点?

是的,您可能需要在这里做一些事情来帮助加快速度。 如前所述,在 std::vector 中保留空间然后将值分配给已知元素会更快。此外,使用非优化编译器时,预递增( ++var 而不是 var++ )更快。只是为了让您的代码保持快速,无论谁构建它,您可能都想从现在开始考虑这样做。就内存而言,您可能会发现它微不足道,但是当我使用无符号且不是不合理大的已知大小时,我会在我的 for 循环中使用无符号 short。

然而,关于模数。如果您不需要它,您可能不想使用它。根据向量中保存的数据类型,如果结果超出该类型的最大存储容量,则应该换行。

我不知道它是否会消耗更多的处理能力来进行变量换行,如果确实如此,我仍然不确定它是否比预模运算更便宜。在使用 rand 之前,可能需要运行一些已知大小的速度测试。

    A.reserve(i * i);
    for(unsigned short j = 0; j < 10; ++j) {            
        for(unsigned short k = 0; k < i; ++k) 
            A[k + (i*10)] = rand();                
        // Other stuff
    }

编辑

需要注意的非常小的变化:循环只进行了 10 次,因此您不妨使用无符号字符,而不是短字符。至少在 Win32 上,它占用一半的内存。

    A.reserve(i * i);
    for(unsigned char j = 0; j < 10; ++j) {            
        for(unsigned char k = 0; k < i; ++k) 
            A[k + (i*10)] = rand();                
        // Other stuff
    }

【讨论】:

  • 可读性比性能更重要,“无论是谁构建的”。 20 年来,后增量与前增量一样快!
  • 哈哈,是的,你当然是对的。当我写这篇文章时,我还在上大学,事后看来,我试图在我没有甚至不知道如何分析的编译器上经历几微秒的疯狂程度,这看起来很愚蠢。我确实更喜欢前增量风格,但这就是我的同事所做的。但是,是的,绝对专注于可读性/可调试性和所有这些好东西。对于样式偏好,如果您正在编写新代码,请坚持原作者使用的内容或项目标准文档。如果今天有人问我,我会这么告诉新手。
【解决方案2】:

来自 cplusplus.com (http://www.cplusplus.com/reference/stl/vector/) 的引用,它提供了一个非常有用的提示:

“就性能而言,重新分配可能是一项代价高昂的操作,因为它们通常涉及要复制到新位置的向量使用的整个存储空间。因此,每当为向量计划大规模增加大小时,它是建议使用成员函数 vector::reserve 明确指示向量的容量。"

使用vector::reserve 几乎肯定会在您的情况下提高性能。

编辑:您可以尝试使用random_shuffle (http://www.cplusplus.com/reference/algorithm/random_shuffle/) 在创建矢量后对其进行洗牌(显然,random_shuffle 在元素数量上是线性的)。

【讨论】:

  • 它几乎肯定只会在第一次运行时这样做。我认为实现并没有真正消除他们在clear() 上的能力。如果他们愿意,我们就不需要交换技巧了。
  • @sbi:感谢您指出这一点,你说得对,clear() 不会缩小矢量,显然,甚至shrink_to_fit() 也肯定不会(stackoverflow.com/questions/2664051/…)。跨度>
【解决方案3】:

我创建一个,看看:

#include <iostream>
#include <cstdlib>
#include <stdio.h>
#include <time.h>
#include <unistd.h>
#include <sstream>

int main(int argc, char* argv[]){
    if (argc < 2){
        printf("No arguments found\n");
        exit(1);
    }
    int maxi;
    maxi = atoi(argv[1]);
    int * a;
    a = new int [5];

    std::stringstream ss;
    ss << maxi;
    printf(ss.str());
    printf("\n");
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-12-29
    • 2018-09-20
    • 2022-01-23
    • 2011-09-16
    • 1970-01-01
    • 1970-01-01
    • 2012-10-13
    • 2010-10-26
    相关资源
    最近更新 更多