How to Work with Random Numbers(怎么使用随机数)

Contents 

The Random Class

  随机类为 Repast 提供了缺省随机数生成器。Random(随机类)是通过由 Colt 库提供的合并的所有随机数的分布将Colt 库的随机数生成器封装到一个单独的类中。这些分布是作为静态实例变量封装的。这里意图有两层:可以较容易使用这些分布,更重要的是确保每一个分布都使用相同的随机数流,允许随机数生成器为简单可重复行为。

  Random 包含一些作为静态实例变量的随机数分布,同样,一些 next*方法用来从一个分布中返回下一个 psuedo 随机值。在使用一些实例变量分布之前,这些分布必须是通过适当 create*方法来产生。例如:

// initialize Random.uniform(初始化 Random.uniform) 
Random.createUniform(); 
// Random.uniform is now initialized and can be used.(Random.uniform
被初始化并被使用) 
int index = Random.uniform.getNextIntFromTo(0, 100);

  这产生一个均匀分布并通过它描述随机数,你就能够使用适当方法从这个分布中来描述随机数。可以在 Colt 文件中 cern.jet.random 封包里看到这些方法详细内容。一个实际的随机数生成器结合当前时间标记在第一次使用中产生。看下面关于产生生成器的详细内容。

  通过 Random 类中的静态实例变量的使用,一次生成的分布就能够用在你的编码中的任何地方。例如,如果你在你的模型方法中生成一个均匀分布,你就可以通过 Random.uniform,在你的 agent 模型编码中访问相同的均匀分布。这个实例量总是应该如此被引用,也就是,作为Random._distribution_name_,而不是作为右手边指派。当设置一个随机种子,用这种方法分配一个变量能够导致不预测的结果。总之,编码应如此:

int index = Random.uniform.nextIntFromTo(0, 10);

  而不能象这样:

Uniform myUniform = Random.uniform; // This is dangerous. Don't do it!!!
... 
int index = myUniform.nextIntFromTo(0, 10);

  但在 Random 类中的每一个分布都是来至于 colt 库。实例变量名是相同的并与colt 对象的第一个字符相一致。例如cern.jet.Random.Zeta 分 布 是Random.zeta。在 colt 库文件中可以看到 cern.jet.random 封包中更多有关这些分布的信息,以及怎么样从中描述随机数的。next*方法可以调用,不需要再去构造这个分布了。例如:

double s = Random.nextCauchy();

  从柯西分布中描述下一个值。

  在所有的例子中,分布使用MersenneTwister 来作为 psuedo 随机数的来源。MersenneTwister 对仿真来说是一个好的特殊生成器,它有一个非常大的周期。这个生成器在第一次传播的时使用当前时刻。然而,Random 也允许你去设置和得到一个随机种子同样随机数生成器与这个种子相关联。用 Random.setSeed 设置一个新种子将会生成一个带有特定种子的新 MersenneTwister,并使得一些以前生成的分布无效。如果你希望在种子被设置以后使用一个分布,你必须象上面所述情况去构造它。从而,下面是正确的编码:

Random.createUniform(); 
int index = Random.uniform.nextIntFromTo(1, 10); 
... 
Random.setSeed(1L); 
Random.createUniform(); 
... 
int index = Random.uniform.nextIntFromTo(1, 10); 
but this is not: 
Random.createUniform(); 
int index = Random.uniform.nextIntFromTo(1, 10); 
... 
Random.setSeed(1L); 
... 
int index = Random.uniform.nextIntFromTo(1, 10); // This won't work

  

  一个 Repast 模型的 setRngSeed 方法也可以设置 Random 的种子,是通过 gui 模型的参数面板来设置的。一旦种子被设置,所有的分布将使用相同的随机数流并反复地随机得到。

  注意 Random 构造一个缺省随机数生成器使用了当前时刻为种子。如果你不明确的设置你的种子,通过 create*来生成这个分布将使用这个缺省的生成器。

  使用这种标准模式将构造一个你想要的分布,通过 Random 实例变量,从那些贯穿你的编码的分布中描述随机数。例如:

Random.createUniform(); 
Random.createNormal(.5, .3); 
... 
int index = Random.uniform.nextIntFromTo(0, 10); 
double val = Random.normal.nextDouble();

  

Custom Random NumberGeneration

  自定义的随机数生成器仍使用 colt 库,但绕过了 Repast 的 Random 类。如果你想使用一个带有独立随机流的分布(随机数生成器),就需要做这些工作。这里一个通用的概念将在你的适当分布类型模型里去定义相同的实例变量,构造你的随机数生成器,并且你想使用的分布与这些生成器关联。例如:

using cern.jet.random;
using MersenneTwister = cern.jet.random.engine.MersenneTwister;
...

public class MyModel : SimModelImpl
{
  
  Normal myNormalDist;
  Uniform myUniformDist;

  ...

  public void begin()
  {
    MersenneTwister generator1 = new MersenneTwister(123);
    MersenneTwister generator2 = new MersenneTwister(321);

    myNormalDist = new Normal(1.0, 1.0, generator1);
    myUniformDist = new Uniform(generator2);
  }

  ...

  public void someMethod()
  {
    int index = myUniformDist.nextIntFromTo(0, 10);
    doubl val = myNormalDist.nextDouble();
 }
}

  这里一个重要的部分就是两个不同的 MersenneTwisters 的构造。针对这个分布,这里将提供两个不同的随机数流。对于这些分布,你可以用参数来表示这些种子,并通过用户界面或通过参数文件的设置来使得它们可用,对于两个种子的值通过提供的取得和设置方法。那么你可以使用种子变量去传播 MersenneTwisters 来代替上面的"123" 和 "321"。如果这些种子是用户特定的,对于在 begin()方法而不是 setup()方法中构造分布来说,它们也是重要的。在 setup()被调用,一个参数变化将会出现,如此构造你的分布将会忽略一些参数变化。

posted @ 2014-12-25 15:14  Buller Lee  阅读(449)  评论(0)    收藏  举报