Java与C+中随机数生成实现的时差+;

Java与C+中随机数生成实现的时差+;,java,c++,montecarlo,Java,C++,Montecarlo,我正在用Java编写一个蒙特卡罗模拟,它涉及到生成许多随机整数。我的想法是,本地代码对于随机数的生成会更快,所以我应该在C++中编写代码,并通过JNI返回输出。但是,当我在C++中写同样的方法时,它执行的时间比java版本要长。以下是代码示例: Random rand = new Random(); int threshold = 5; int[] composition = {10, 10, 10, 10, 10}; for (int j = 0; j < 100000000; j++)

我正在用Java编写一个蒙特卡罗模拟,它涉及到生成许多随机整数。我的想法是,本地代码对于随机数的生成会更快,所以我应该在C++中编写代码,并通过JNI返回输出。但是,当我在C++中写同样的方法时,它执行的时间比java版本要长。以下是代码示例:

Random rand = new Random();
int threshold = 5;
int[] composition = {10, 10, 10, 10, 10};
for (int j = 0; j < 100000000; j++) {
    rand.setSeed(System.nanoTime());
    double sum = 0;
    for (int i = 0; i < composition[0]; i++) sum += carbon(rand);
    for (int i = 0; i < composition[1]; i++) sum += hydrogen(rand);
    for (int i = 0; i < composition[2]; i++) sum += nitrogen(rand);
    for (int i = 0; i < composition[3]; i++) sum += oxygen(rand);
    for (int i = 0; i < composition[4]; i++) sum += sulfur(rand);
    if (sum < threshold) {}//execute some code
    else {}//execute some other code
}
Random rand=new Random();
int阈值=5;
int[]组合={10,10,10,10,10};
对于(int j=0;j<100000000;j++){
rand.setSeed(System.nanoTime());
双和=0;
对于(int i=0;i
以及C++中的等效代码:

int threshold = 5;
int composition [5] = {10, 10, 10, 10, 10};
for (int i = 0; i < 100000000; i++)
{
    srand(time(0));
    double sum = 0;
    for (int i = 0; i < composition[0]; i++) sum += carbon();
    for (int i = 0; i < composition[1]; i++) sum += hydrogen();
    for (int i = 0; i < composition[2]; i++) sum += nitrogen();
    for (int i = 0; i < composition[3]; i++) sum += oxygen();
    for (int i = 0; i < composition[4]; i++) sum += sulfur();
    if (sum > threshold) {}
    else {}
}
int阈值=5;
整数合成[5]={10,10,10,10,10};
对于(int i=0;i<100000000;i++)
{
srand(时间(0));
双和=0;
对于(int i=0;i阈值){}
else{}
}
所有元素方法(碳、氢等)只生成一个随机数并返回一个双精度

运行时为java代码77.471秒,C++为121.777秒。 当然,我在C++中不是很有经验,所以可能是因为写的代码写得不好。

< P> java(实际上JIT)通常很擅长检测没有任何有用的代码。这是因为JIT可以在运行时获得静态编译器无法确定的信息。对于可以被优化的代码,java实际上可以比C++更快。然而,通常,一个良好的C++程序比java中的程序快。 简而言之,给定任何时间,C++将是一个很好理解、调整好的程序的更快。然而,给定有限的资源,不断变化的需求和混合能力的团队,java通常可以比C++大幅度地超越。
<> P>>所有的,可能是C++中的随机性更好,但更昂贵。

< P>我怀疑性能问题是在你的代码> CUBE()中的代码< >代码>氢>(<代码)>代码> >氮()/代码>,<代码>氧()/<代码>,和 Sulle()/<代码>函数。你应该展示他们是如何产生随机数据的

或者它可以在
if(sum
代码中

我想继续设定种子,这样结果就不会是确定性的(更接近于真正的随机性)

由于您使用时间(0)
的结果作为种子,因此无论哪种方式,您都不会得到特别随机的结果

您不应该使用
srand()
rand()
而是应该查看
库,选择具有满足您需要的性能/质量特征的发动机。如果您的实现支持它,您甚至可以从
std::random_device
获取非确定性随机数据(生成种子或作为引擎)

另外,
提供了预先制作的发行版,如
std::uniform\u real\u发行版
,这可能比普通程序员从
rand()的结果手动计算所需发行版的方法要好


好的,下面是如何从代码中消除内部循环并大幅提高速度(在Java或C++中)

您的代码:

double carbon() {
  if (rand() % 10000 < 107)
    return 13.0033548378;
  else
    return 12.0;
}
您将得到
sum+=X*13.0033548378+Y*12.0其中X是随机数保持在阈值以下的次数,Y是(试验-X)。恰好您可以模拟运行一系列试验,并使用二项分布计算成功的数量,
恰好提供了二项分布

给定一个函数
sum\u trials()

我没有您正在使用的实际值,但您的整个循环将类似于:

  for (int i = 0; i < 100000000; i++) {
     double sum = 0;
     sum += sum_trials(composition[0], 107.0/10000.0, 13.003354378, 12.0); // carbon trials
     sum += sum_trials(composition[1], 107.0/10000.0, 13.003354378, 12.0); // hydrogen trials
     sum += sum_trials(composition[2], 107.0/10000.0, 13.003354378, 12.0); // nitrogen trials
     sum += sum_trials(composition[3], 107.0/10000.0, 13.003354378, 12.0); // oxygen trials
     sum += sum_trials(composition[4], 107.0/10000.0, 13.003354378, 12.0); // sulfur trials

     if (sum > threshold) {
     } else {
     }
   }
代码的原始版本花费了我的系统大约1分30秒。这里的最后一个版本需要11秒


这是一个函子,用两个二项式分布生成氧和。也许其他发行版中的一个可以一次性完成,但我不知道

struct sum_trials2 {
  std::binomial_distribution<> d1;
  std::binomial_distribution<> d2;
  double A; double B; double C;
  int trials;
  double probabilty2;

  sum_trials2(int t, double p1, double p2, double a, double b, double c)
    : d1{t, p1}, A{a}, B{b}, C{c}, trials{t}, probability2{p2} {}

  double operator() () {
    int X = d1(eng);
    d2.param(std::binomial_distribution<>{trials-X, p2}.param());
    int Y = d2(eng);

    return X*A + Y*B + (trials-X-Y)*C;
  }
};

sum_trials2 oxygen{composition[3], 17.0/1000.0, (47.0-17.0)/(1000.0-17.0), 17.9999, 16.999, 15.999};
除非其他元素的值为负值,否则总和大于5的概率为100%。在这种情况下,您甚至不需要生成随机数据;执行代码的“if”分支100000000次

int main() {
  for (int i=0; i< 100000000; ++i) {
    //execute some code
  }
}
intmain(){
对于(int i=0;i<100000000;++i){
//执行一些代码
}
}

你有没有为C++版本启用编译器优化?JNI的开销可能超过试图在java中使用C++的任何性能收益。@ OLICHARSVESY我一直使用GCC编译器来解决CodeBlocks IDEWhat的问题吗?你是在寻找一个解释还是一个让C++代码更快的方法?好的,使用<代码> Gcc-O3,我可以复制你的结果。我没有确定的源代码,但我怀疑
java.util.Random
的方法是JVM中的内在操作,或者java随机数生成不同(=更快)。另一方面,
gcc
只有一次机会进行优化,而JIT有更多的时间进行优化(在迭代中)。碳、氢等方法非常简单,它们都与此类似:私有双碳(){if(rand()%10000<107)返回13.003354
  for (int i = 0; i < 100000000; i++) {
     double sum = 0;
     sum += sum_trials(composition[0], 107.0/10000.0, 13.003354378, 12.0); // carbon trials
     sum += sum_trials(composition[1], 107.0/10000.0, 13.003354378, 12.0); // hydrogen trials
     sum += sum_trials(composition[2], 107.0/10000.0, 13.003354378, 12.0); // nitrogen trials
     sum += sum_trials(composition[3], 107.0/10000.0, 13.003354378, 12.0); // oxygen trials
     sum += sum_trials(composition[4], 107.0/10000.0, 13.003354378, 12.0); // sulfur trials

     if (sum > threshold) {
     } else {
     }
   }
struct sum_trials {
  std::binomial_distribution<> dist;
  double A; double B; int trials;

  sum_trials(int t, double p, double a, double b) : dist{t, p}, A{a}, B{b}, trials{t} {}

  double operator() () {
    int successes = dist(eng);
    return successes * A + (trials - successes) * B;
  }
};

int main() {
  int threshold = 5;
  int composition[5] = { 10, 10, 10, 10, 10 };

  sum_trials carbon   = { composition[0], 107.0/10000.0, 13.003354378, 12.0};
  sum_trials hydrogen = { composition[1], 107.0/10000.0, 13.003354378, 12.0};
  sum_trials nitrogen = { composition[2], 107.0/10000.0, 13.003354378, 12.0};
  sum_trials oxygen   = { composition[3], 107.0/10000.0, 13.003354378, 12.0};
  sum_trials sulfur   = { composition[4], 107.0/10000.0, 13.003354378, 12.0};


  for (int i = 0; i < 100000000; i++) {
     double sum = 0;

     sum += carbon();
     sum += hydrogen();
     sum += nitrogen();
     sum += oxygen();
     sum += sulfur();

     if (sum > threshold) {
     } else {
     }
   }
}
struct sum_trials2 {
  std::binomial_distribution<> d1;
  std::binomial_distribution<> d2;
  double A; double B; double C;
  int trials;
  double probabilty2;

  sum_trials2(int t, double p1, double p2, double a, double b, double c)
    : d1{t, p1}, A{a}, B{b}, C{c}, trials{t}, probability2{p2} {}

  double operator() () {
    int X = d1(eng);
    d2.param(std::binomial_distribution<>{trials-X, p2}.param());
    int Y = d2(eng);

    return X*A + Y*B + (trials-X-Y)*C;
  }
};

sum_trials2 oxygen{composition[3], 17.0/1000.0, (47.0-17.0)/(1000.0-17.0), 17.9999, 16.999, 15.999};
int main() {
  std::minstd_rand0 eng;
  std::bernoulli_distribution dist(probability_sum_is_over_threshold);

  for (int i=0; i< 100000000; ++i) {
    if (dist(eng)) {
    } else {
    }
  }
}
int main() {
  for (int i=0; i< 100000000; ++i) {
    //execute some code
  }
}