std :: normal_distribution <double>会导致错误的订单窗口与Linux相比?

use*_*667 4 c++ linux random stl

有人来访问这个问题吗?每1个实现不需要生成相同的数据.在实践中怎么样 - 在arm,x86,免费和商业编译器中STL实现有很多不同之处?

// g++ --std=c++11 -o a minimal.cpp && ./a

#include <iostream>
#include <random>

using namespace std;

int
main()
{
  std::mt19937_64 gen;
  gen.seed(17);

  cout << "\nNormal\n";
  normal_distribution<double> distr1;
  for (int i = 0; i < 2; i++) {
    double delay = distr1(gen);
    printf("  Value = %15.15g\n", delay);
  }
  return(0);
}


/*

Results

(1) gcc-4.8.0 linux 64b version result
  Normal
    Value = 1.03167351251536
    Value = 1.21967569130525
(2) Microsoft Visual Studio Community 2015 Version 14.0.23107.0 D14REL
      or 
    Microsoft Visual Studio Professional 2012 Version 11.0.60610.01 Update 3
  Normal
    Value = 1.21967569130525
    Value = 1.03167351251536  // same values in wrong (different) order
*/
Run Code Online (Sandbox Code Playgroud)

我可以理解在一些特殊的硬件平台上使用不同的算法来生成或分配,但这种差异似乎更像是一个bug.

这里有一些代码我用来诊断差异来自哪里并解决它: - win和linux上的生成器和统一分布匹配. - 除了成对顺序之外,正态分布在数字上匹配

//   g++ --std=c++11 -o a workaround.cpp && ./a


#include <iostream>
#include <random>
#include <stack>


using namespace std;

typedef  std::mt19937_64  RandGenLowType;

// Helper wrapper - it did confirm that the differences
// do NOT come from the generator
class RandGenType : public RandGenLowType {
  public:
    result_type operator()() {
      result_type val = RandGenLowType::operator()();
      printf("    Gen pulled %20llu\n", val);
      return(val);
    }
};


typedef normal_distribution<double> NormalDistrLowType;

// Workaround wrapper to swap the output data stream pairwise
class NormalDistrType : NormalDistrLowType {
  public:
    result_type operator()(RandGenType &pGen) {
      // Keep single flow (used variables, includes) same for all platforms
      if (win64WaStack.empty()) {
        win64WaStack.push(NormalDistrLowType::operator()(pGen));
#ifdef _MSC_VER
        win64WaStack.push(NormalDistrLowType::operator()(pGen));
#endif
      }
      result_type lResult = win64WaStack.top();
      win64WaStack.pop();
      return(lResult);
    }    
  private:
    std::stack<result_type> win64WaStack;
};


int
main()
{
  RandGenType gen;
  gen.seed(17);

  // No platform issue, no workaround used
  cout << "\nUniform\n";
  uniform_real_distribution<double> distr;
  for (int i = 0; i < 4; i++) {
    double delay = distr(gen);
    printf("  Delay = %15.15g\n", delay);
  }

  // Requires the workaround
#ifdef _MSC_VER
  cout << "Workaround code is active, swapping the output stream pairwise\n";
#endif
  cout << "\nNormal\n";
  //normal_distribution<float> distr1;
  NormalDistrType distr1;
  for (int i = 0; i < 10; i++) {
    double delay = distr1(gen);
    printf("  Value = %15.15g\n", delay);
  }
  return(0);
}
Run Code Online (Sandbox Code Playgroud)

T.C*_*.C. 6

生成正态分布随机数的几种常用方法,例如Box-Muller变换Marsaglia极坐标方法,一次生成两个随机数.使用这些方法之一的分发对象将生成两个随机数,返回其中一个,并在下次调用时保存另一个.

当然,返回哪一个以及存储哪一个完全取决于图书馆作者.看起来libstdc ++和MSVC使用相同的算法,但碰巧选择不同.