【问题标题】:Random numbers Mathematica vs Java随机数 Mathematica 与 Java
【发布时间】:2011-02-12 09:45:04
【问题描述】:

哪个集合更“随机”?

Math.random() 用于 Java 还是 random 用于 Mathematica? Java 为蓝色,Mathematica 为红色。

数字从 0 到 50(51?)

编辑: 这是在 Mathematica 中生成的直方图。

Java源码(丑)

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        int i = 0;
        int sum = 0;
        int counter = 0;
        String randomNumberList = " ";
        int c = 0;
        while (c != 50){

            while (i != 7) {
            i = (int) (51 * Math.random());
            sum += i;
            ++counter;
            randomNumberList += " " + i;
            }
        i = 0;
        System.out.print("\n" + randomNumberList);
        ++c;
        }

    }

Mathematica 源代码(output.txt 是 Java 的转储文件)

dataset = ReadList["~/Desktop/output.txt", Number] 
dataset2 = RandomReal [{0, 50}, 50000]
Histogram[{dataset, dataset2}]

[编辑]:我在编写代码时只是在学习循环。对困惑感到抱歉。现在我制作了一个更简洁的版本,它们的分布大致相同。我猜任意循环结束会产生很大的不同。

新代码:

public class RandomNums {

  public static void main(String[] args) {
    int count = 0;
    for (int i = 0; i <= 50000; i++){
        int j = (int) (50 * Math.random());
        System.out.print(j + " ");
        count++;
        if (count == 50){
            System.out.println("\n");
            count = 0;
        }
     }
  }
}

【问题讨论】:

  • 您将不得不解释更多关于该图表所代表的内容。看起来它可能是一个直方图,但很难说。请附上源代码。
  • 你是如何生成数字的?
  • 随机性的“质量”需要的不仅仅是直方图。您必须查看生成的各种系列。可能有整本关于它的书。
  • @Gabe:说得好!作为一个简单的例子,我可以简单地使用递增的模计数器生成一个具有完全平坦分布的序列。
  • 你为什么有while(i!=7)?我不知道您的 Java 代码生成了多少个数字。为什么不在一个循环中生成 50000 个随机数?

标签: java random wolfram-mathematica


【解决方案1】:

如果这个图对我有什么建议,那就是 Mathematica 的均匀随机分布的质量比您展示的 Java 中的实现要好得多(我不主张任何 Java 实现。另外,作为免责声明,而不是引发一场激烈的战争,我已经有一段时间既是 J2EE 又是 Mathematica 开发人员,尽管我承认在后者方面有更多的经验)。

这里是论据。您显示了 50000 个点和 50 个箱(直方图条),这表明您每个箱大约有 1000 个点。更准确地说,我们可以使用遍历性将 50000 个均匀分布点的问题转换为 50000 个独立试验的问题,并询问每个 bin 中的平均点数是多少,以及方差是多少。然后由二项分布给出任何特定 bin 最终恰好是 k 点超出 Npoints 的概率:

对于其中,均值是Npoints/Nbins(当然,这是我们直观地期望的),方差是Npoints * (1-1/Nbins)* 1/Nbins ~ Npoints/Nbins = 1000,在我们的例子中是(Npoints = 50000, Nbins = 50)。取平方根,我们得到标准差为sqrt(1000) ~ 32,大约是平均值的 3%(即1000)。结论是,对于理想的均匀分布,以及给定数量的点和 bin,我们应该预期每个 bin 与平均值的偏差约为 3%。从图片来看,这与 Mathematica 分布给我们的非常相似。 Java 分布的各个 bin 的偏差(同样,这里介绍的特定实现)要大得多,并且表明 bin 之间存在相关性,并且总体上这种均匀分布的质量要差得多。

现在,这是一个“高级”论点,我不会详细说明原因。然而,这似乎是合乎逻辑的,因为 Mathematica 的传统目标受众(科学、学术界)在这方面(或至少曾经是)比 Java 要求更高。也就是说,我毫不怀疑存在许多用于许多统计分布的随机数生成器的优秀 Java 实现——它们只是没有内置在语言中,不像在 Mathematica 中。

【讨论】:

  • @Leonid +1 我认为应该能够对此进行一些假设测试(肯定有争议)。
  • @belisarius 好吧,无论如何,这不会是我很快:)
  • @Leonid 我们应该找一个替罪羊来责备不这样做:D
  • +1 表示“存在许多优秀的 Java 实现......” - @LQDC - 您应该查看 Mersenne Twister 实现。它是一个周期为 2^19937 - 1 的伪随机数生成器。查看 Wikipedia 上的这篇文章以获取更多信息,以及该算法的各种实现。 en.wikipedia.org/wiki/Mersenne_twister
  • Java 代码使用较小的样本量,这为合并计数提供了更高的方差。使用 WReach 的代码,我得到几乎相同的直方图
【解决方案2】:

不是对这个问题的直接回答......但任何想要执行@belisarius 建议的一些“假设检验”以回应@Leonid 的人可能会发现以下代码 sn-p 有助于在没有的情况下进行尝试离开 Mathematica:

Needs["JLink`"]

(* Point to a different JVM if you like... *)
(* ReinstallJava[CommandLine -> "...", ClassPath-> "..."] *)

ClearAll@JRandomInteger
JRandomInteger[max_, n_:1] := JRandomInteger[{0, max}, n]
JRandomInteger[{min_, max_}, n_:1] :=
  JavaBlock[
    Module[{range, random}
    , range = max - min + 1
    ; random = JavaNew["java.util.Random"]
    ; Table[min + random@nextInt[range], {n}]
    ]
  ]

Histogram[
  Through[{JRandomInteger, RandomInteger}[{0, 50}, 50000]]
, ChartLegends->{"Java","Mathematica"}
]

请注意,此 sn-p 使用 Random.nextInt() 而不是 Math.random() 试图更好地处理这个棘手的上限。

【讨论】:

  • 顺便说一下,当我在我的机器(MMA 8、Java 6)上运行这段代码时,两个分布都非常一致。我没有看到原始问题中表现出的不统一行为。
【解决方案3】:

看看here。它处理 java.util.Random 并显示一些问题。如果您想要更真实的(:-))随机性,它还建议使用SecureRandom(更昂贵,更安全)。

【讨论】:

    【解决方案4】:

    我发现一个非常平坦的分布很可疑,因为它应该是随机的。

    以下代码打印出我希望看到的内容,即由于随机性而导致的出现次数的变化。

    Random : min count 933, max count 1089
    Random : min count 952, max count 1071
    Random : min count 922, max count 1056
    Random : min count 936, max count 1083
    Random : min count 938, max count 1063
    SecureRandom : min count 931, max count 1069
    SecureRandom : min count 956, max count 1070
    SecureRandom : min count 938, max count 1061
    SecureRandom : min count 958, max count 1100
    SecureRandom : min count 929, max count 1068
    /dev/urandom: min count 937, max count 1093
    /dev/urandom: min count 936, max count 1063
    /dev/urandom: min count 931, max count 1069
    /dev/urandom: min count 941, max count 1068
    /dev/urandom: min count 931, max count 1080
    

    代码

    import java.io.*; 
    import java.security.SecureRandom; 
    import java.util.Random;
    
    public class Main {
        public static void main(String... args) throws IOException {
            testRandom("Random ", new Random());
            testRandom("SecureRandom ", new SecureRandom());
            testRandom("/dev/urandom", new DevRandom());
        }
    
        private static void testRandom(String desc, Random random) {
            for (int n = 0; n < 5; n++) {
                int[] counts = new int[50];
                for (int i = 0; i < 50*1000; i++)
                    counts[random.nextInt(50)]++;
                int min = Integer.MAX_VALUE, max = Integer.MIN_VALUE;
                for (int count : counts) {
                    if (min > count) min = count;
                    if (max < count) max = count;
                }
                System.out.println(desc+": min count " + min + ", max count " + max);
            }
        }
    
        static class DevRandom extends Random {
            DataInputStream fis;
    
            public DevRandom() {
                try {
                    fis = new DataInputStream(new BufferedInputStream(new FileInputStream("/dev/urandom")));
                } catch (FileNotFoundException e) {
                    throw new AssertionError(e);
                }
            }
    
            @Override
            protected int next(int bits) {
                try {
                    return fis.readInt();
                } catch (IOException e) {
                    throw new AssertionError(e);
                }
            }
    
            @Override
            protected void finalize() throws Throwable {
                super.finalize();
                if (fis != null) fis.close();
            }
        } 
     }
    

    【讨论】:

      【解决方案5】:

      使用正确编写的随机代码:

      public static void main(String[] args) {
          String randomNumberList = " ";
          for (int c = 0; c < 50000; ++c) {
              // random integer in the range 0 <= i < 50
              int i = (int) Math.floor(50 * Math.random());
              System.out.print(i + " ");
          }
      }
      

      我没有看到你所说的差异

                       *      *                         
        **   * * ** * ***  ** ***  ** *   *  * *   **** 
      ****** **************** **************************
      **************************************************
      **************************************************
      **************************************************
      **************************************************
      **************************************************
      **************************************************
      **************************************************
      **************************************************
      **************************************************
      **************************************************
      **************************************************
      **************************************************
      **************************************************
      **************************************************
      **************************************************
      **************************************************
      **************************************************
      **************************************************
      

      生成图形的 Python 代码:

      #!/usr/bin/env python
      s = raw_input()
      nums = [int(i) for i in s.split()]
      bins = dict((n,0) for n in range(50))
      for i in nums:
          bins[i] += 1
      
      import itertools
      heightdivisor = 50 # tweak this to make the graph taller/shorter
      xx = ['*'*(v / heightdivisor) for k,v in bins.items()]
      print '\n'.join(reversed([''.join(x) for x in itertools.izip_longest(*xx, fillvalue=' ')]))
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2016-04-15
        • 1970-01-01
        • 1970-01-01
        • 2014-03-08
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多