C++ 标准::统一实分布与标准::统一内部分布性能

C++ 标准::统一实分布与标准::统一内部分布性能,c++,performance,random,floating-point,C++,Performance,Random,Floating Point,我在我的一个应用程序中遇到了性能下降的问题,我将其归咎于随机数据的生成。我编写了一个简单的基准测试,基本上也是这样做的: #include <chrono> #include <iostream> #include <random> std::mt19937 random_engine{std::random_device()()}; // Generate one million random numbers template <typename

我在我的一个应用程序中遇到了性能下降的问题,我将其归咎于随机数据的生成。我编写了一个简单的基准测试,基本上也是这样做的:

#include <chrono>
#include <iostream>
#include <random>

std::mt19937 random_engine{std::random_device()()};

// Generate one million random numbers
template <typename T, typename Distribution>
std::vector<T> generate_random(Distribution distribution) {
  std::vector<T> data(1000000);

  std::generate_n(data.begin(), 1000000, [&]() {
    return static_cast<T>(distribution(random_engine));
  });
  return data;
}

template <typename T>
std::vector<T> create_data() {
  if constexpr (std::is_same_v<T, float>)
    return generate_random<float>(
        std::uniform_real_distribution<float>(-127.0f, 127.0f));
  if constexpr (std::is_same_v<T, int8_t>)
    return generate_random<int8_t>(
        std::uniform_int_distribution<int32_t>(-127, 127));
}

int main() {
  auto start = std::chrono::system_clock::now();
  auto float_data = create_data<float>();
  std::cout << "Time (float): " << (std::chrono::system_clock::now() - start).count()
            << '\n';

  start = std::chrono::system_clock::now();
  auto int8_data = create_data<int8_t>();
  std::cout << "Time (int8): " << (std::chrono::system_clock::now() - start).count()
            << '\n';

  return 0;
}
为什么从真实分布采样比从int分布采样花费的时间少

更新


libc++和libstdc++表现出完全相反的行为。我仍在研究实现上的差异所在。请参阅V/P/>< P>回忆随机数分布的C++标准,包括<代码>一致性In分布>代码> >代码> SimultRealOffic发行< <代码> < < <>你将不得不调查C++标准库的具体实现(这对于CLAN编译器来说通常是很容易的,因为它倾向于使用开源库<代码> LBSTDC++< /COD>)。但是,在间隔[a,b]中生成浮点数(例如
float
)与在同一间隔中生成整数之间存在差异:

  • 浮点数:在大多数实际情况下,给定区间中的浮点数多于该区间中的整数。实现可以通过在[0,1]中生成统一的随机浮点数来生成一定范围内的统一浮点数(例如通过使用
    生成正则表达式
    ,其规范到目前为止不幸存在缺陷),然后缩放该数字以适应
    均匀实分布
    给出的范围。这可能涉及使用浮点乘法、除法或其他运算
  • 整数:在一个范围内生成整数通常需要生成足够的随机位以适应该范围,然后使用模减少或拒绝采样(后者是无偏的)。该过程将倾向于不使用浮点运算(与整数运算相比,浮点运算相对较慢),这可以解释您发现的性能差异

测量未优化的代码是没有意义的。打开优化(-O3)看看你会得到什么。基准测试的第一条规则:始终使用优化进行构建。使用代码启用优化与不启用优化之间有很大的区别(一旦添加了实际运行的程序缺少的
?(例如,请参见差异,未优化的代码是2000多行汇编代码,优化的大约500行)。非常正确,感谢您选择@NathanOliver。虽然使用-O3,结果是相同的。我更新了答案您的代码有未定义的行为。在
std::uniform_int_distribution(127,-127)中
首先应该是
-127
。修复后仍然会得到相同的结果,我不确定为什么会这样,我将把它留给其他人。结果似乎取决于很多事情。我在编译器资源管理器上用不同的变体和不同的编译器进行了实验。使用Clang,它始终为
int8\t提供较小的数字,而GCC则相反。使用不同的实现(例如,如果constexpr
,则使用专门化而不是
)除了使用
int32_t
添加第三个测试时,
int8_t
情况突然改善外,没有任何区别。最后,在
generate_random
中删除该
静态强制转换有助于整体。感谢链接。这确实很可能是由于发行版的libc++实现。您在表示整数分布的生成速度应该更快,但这里的情况并非如此。事实上,libstdc++和libc++表现出完全相反的行为,因此这可能不是因为在生成过程中使用或未使用浮点运算。我还测试了double的性能,它比float慢,但仍然比任何I恩泰格类型。
〉g++ -v
...
Apple clang version 11.0.3 (clang-1103.0.32.29)
Target: x86_64-apple-darwin19.5.0
...

〉g++ tmp.cpp -std=c++17 -O3 && ./a.out
Time (float): 68033
Time (int8): 172771