在 (C++) boost::random 和 C++ STL 中,卡方分布比 boost::math 更快吗?

计算科学 C++ 表现 统计数据 随机数生成
2021-12-11 11:06:20

我正在尝试根据某种自由度(可以是浮点数)在 C++ 中生成随机卡方数。有几个库可用于此目的,其中包含头文件的 C++11 标准库<random>,或两个 Boost 库,boost::mathboost::random.

这些库没有完全相同的用户界面,但更令人惊讶的是,它们生成数字的速度绝对不同。我已经使用下一个玩具代码进行了测试:

  #include <chrono>
  #include <random>
  #include <boost/math/distributions/chi_squared.hpp>
  #include <boost/random/chi_squared_distribution.hpp>

  unsigned int N = 1e6; 
  double df = 2.4;      //degree of freedom for chi-square

  //generator and distributions  
  std::mt19937 gen;  //random number engine, boost::mt19937 doesn't change anything
  std::chi_squared_distribution<> chi2STL(df); //STL implementation
  boost::random::chi_squared_distribution<> chi2BoostRandom(df); //boost::random 
  boost::math::chi_squared chi2BoostMath(df); //boost::math
  boost::uniform_real<> unif(0., 1.); //uniform distribution for boost::math
                                      //taking STL implementation does not change anything

  //time measure
  auto point1 = std::chrono::high_resolution_clock::now();

  //generate chi2 numbers with STL
  for(unsigned int i = 0; i < N; ++i)
  {
    chi2STL(gen);
  }

  auto point2 = std::chrono::high_resolution_clock::now();

  //generate chi2 numbers with boost::random
  for(unsigned int i = 0; i < N; ++i)
  {
    chi2BoostRandom(gen);
  }

  auto point3 = std::chrono::high_resolution_clock::now();

  //generate chi2 numbers with boost::math
  for(unsigned int i = 0; i < N; ++i)
  {
    boost::math::quantile(chi2BoostMath, unif(gen));
  }

  auto point4 = std::chrono::high_resolution_clock::now();

  //get time
  std::cerr << "Time STL loop: "   << std::chrono::duration_cast<std::chrono::microseconds>(point2 - point1).count()/1000000. << " s" << std::endl;
  std::cerr << "Time Boost Random loop: " << std::chrono::duration_cast<std::chrono::microseconds>(point3 - point2).count()/1000000. << " s" << std::endl;
  std::cerr << "Time Boost Math loop: "   << std::chrono::duration_cast<std::chrono::microseconds>(point4 - point3).count()/1000000. << " s" << std::endl;

使用下一个输出:

Time STL loop: 0.474826 s
Time Boost Random loop: 0.374868 s
Time Boost Math loop: 5.02392 s

事实证明 boost::math 方法比其他两个方法慢得多。我使用正规定律而不是卡方定律对这个令人惊讶的点进行了更多调查。在这种情况下,所有三种方法都以相同的速度产生数字,这让我认为 boost::quantile 方法不是耗时的方法。

顺便说一句,我检查了生成的数字,这些数字似乎都符合卡方定律,至少对于我的需要而言。

boost::math 中实现的方法似乎比其他两个方法效率低。(可悲的是,它是我在网上找到实现细节的唯一一个:它利用了不完全伽马函数的数值计算)。

这种简单化的解释正确吗?在这种情况下,不应该弃用 boost::math 实现吗?

0个回答
没有发现任何回复~