【问题标题】:Generate random values in C#在 C# 中生成随机值
【发布时间】:2010-10-15 05:03:30
【问题描述】:

如何在 C# 中使用 Random 类生成随机 Int64 和 UInt64 值?

【问题讨论】:

    标签: c# random long-integer int64


    【解决方案1】:

    这应该可以解决问题。 (它是一种扩展方法,因此您可以像在 Random 对象上调用普通的 NextNextDouble 方法一样调用它。

    public static Int64 NextInt64(this Random rnd)
    {
        var buffer = new byte[sizeof(Int64)];
        rnd.NextBytes(buffer);
        return BitConverter.ToInt64(buffer, 0);
    }
    

    如果您想要无符号整数,只需将 Int64 替换为 UInt64 即可,一切正常。

    注意:由于没有提供关于生成数字的安全性或所需随机性的上下文(实际上 OP 特别提到了 Random 类),我的示例仅处理 Random类,当随机性(通常量化为information entropy)不是问题时,这是首选解决方案。有趣的是,请参阅提到 RNGCryptoServiceProviderSystem.Security 命名空间中提供的 RNG)的其他答案,它们的使用几乎相同。

    【讨论】:

    • +1 用于向 OP 提供他们所要求的内容,并提及使用 Random 的限制,并在 Random 的限制对预期用途过于严格时提供替代方案。
    • 请注意,这种方法也返回负数和 Int64.MaxValue,而 System.Random.Next() 被限制为正数,包括 0 但没有 Int32.MaxValue。
    • @Christoph:是的,观察得很好。但是,您可以通过忽略缓冲区的 MSB(最高有效位)很容易地修改我的方法以仅产生正值。
    • 我尝试实施此解决方案,但发现结果并不是令人满意的随机性。在生成了数千个数字后,我发现绝大多数数字是 19 位,偶发数字是 18 位,非常罕见的数字是 17 位。在我生成的数千个数字中,我从未见过任何 16 位或更少的数字。如何修改此解决方案以解决此问题?
    • @kd7iwp:我担心你对这里的“随机”有一个有点困惑的看法。这里的关键是生成值的分布。整数是否均匀分布?是的,当然,因为它们的位是独立且统一的随机变量。现在观察到 (n + 1) 位数的数字是 n 位数的大约 10 倍,这对您来说应该足够清楚了。
    【解决方案2】:

    使用Random.NextBytes()BitConverter.ToInt64 / BitConverter.ToUInt64

    // Assume rng refers to an instance of System.Random
    byte[] bytes = new byte[8];
    rng.NextBytes(bytes);
    long int64 = BitConverter.ToInt64(bytes, 0);
    ulong uint64 = BitConverter.ToUInt64(bytes, 0);
    

    请注意,使用 Random.Next() 两次,移动一个值,然后 ORing/adding 不起作用。 Random.Next() 只产生非负整数,即它产生 31 位,而不是 32 位,因此两次调用的结果只产生 62 位随机位,而不是覆盖 Int64/UInt64 的完整范围所需的 64 位。 (Guffa's answer 展示了如何通过 三个 调用 Random.Next() 来做到这一点。)

    【讨论】:

    • 哦,很好(评论)——我正在删除我的,因为 BitConverter 等已经被很好地覆盖了......
    • 好的 - 我把它放在我的答案中,而不仅仅是评论,这样它会更明显。无论如何,我将把它留在现在作为对未来的警告(否则它是一个明显的选择)。
    • 由于大多数 lcm PRNG 的低位随机性较小,生成 2 个数字并将它们连接在一起可能会引入细微的偏差......
    • @JonSkeet Random 值是均匀分布的。我不确定我们是否会通过以下方法获得均匀分布的值,尤其是在我们放弃 MSB 的情况下。我们还可以从 2 个随机数中获取一个值,如果第二次调用是 random.Next(int.MinValue, int.MaxValue),那么所有字节都将被填充。
    • @AlexZhukovskiy:这完全改变了您的反对意见,并且基于实现细节。你可以通过 3 次调用 Random.Next 来完成,即使你想要完整的范围,因为每次调用都会生成 31 位随机数据​​,而我们总共只需要 64 位。
    【解决方案3】:

    给你,这使用 crytpo 服务 (不是Random 类),它(理论上)是比 Random 类更好的 RNG。您可以轻松地将其作为 Random 的扩展或创建自己的 Random 类,其中 RNGCryptoServiceProvider 是类级对象。

    using System.Security.Cryptography;
    public static Int64 NextInt64()
    {
       var bytes = new byte[sizeof(Int64)];    
       RNGCryptoServiceProvider Gen = new RNGCryptoServiceProvider();
       Gen.GetBytes(bytes);    
       return BitConverter.ToInt64(bytes , 0);        
    }
    

    【讨论】:

    • 这绝对值得一提,尽管从问题来看,OP似乎不太关心生成数字的随机性。同样重要的是要意识到 RNGCryptoServiceProvider 比 Random 慢很多(尽管性能在这里可能很重要,也可能无关紧要)。
    【解决方案4】:

    您可以使用位移将 31 位随机数组合成一个 64 位随机数,但您必须使用三个 31 位数字才能获得足够的位数:

    long r = rnd.Next();
    r <<= 31;
    r |= rnd.Next();
    r <<= 31;
    r |= rnd.Next();
    

    【讨论】:

      【解决方案5】:

      我总是使用它来获取我的随机种子(为简洁起见,删除了错误检查):

      m_randomURL = "https://www.random.org/cgi-bin/randnum?num=1&min=1&max=1000000000";
      HttpWebRequest req = (HttpWebRequest)WebRequest.Create(m_randomURL);
      StreamReader stIn = new StreamReader(req.GetResponse().GetResponseStream());
      Random rand = new Random(Convert.ToInt32(stIn.ReadToEnd()));
      

      random.org 使用大气噪声来产生随机性,显然用于彩票等。

      【讨论】:

        【解决方案6】:

        你没有说你将如何使用这些随机数...请记住,Random 返回的值不是“加密安全”的,它们不应该用于涉及(大)秘密或(大量)金钱的事情。

        【讨论】:

        • -1 未提及 .Net Crypto RNG。 msdn.microsoft.com/en-us/library/…
        • 为什么相关? Dan 提到 PC 无法生成加密安全随机数这一事实。 RNGCryptoServiceProvider 类不能解决这个问题。
        • 并且 RNGCryptoServiceProvider 生成加密安全的随机数并满足他的回答条件。
        • 约翰·冯·诺依曼:“任何考虑产生随机数字的算术方法的人,当然都处于犯罪状态。”
        • 提问者没有提到他需要一个安全的随机数,但很高兴您指出 Random 类不产生安全数,但您确实应该提及替代方案而不是留下死胡同.
        【解决方案7】:

        您可以创建一个byte 数组,用随机数据填充它,然后将其转换为long (Int64) 或ulong (UInt64)。

        byte[] buffer = new byte[sizeof(Int64)];
        Random random = new Random();
        
        random.NextBytes(buffer);
        long signed = BitConverter.ToInt64(buffer, 0);
        
        random.NextBytes(buffer);
        long unsigned = BitConverter.ToUInt64(buffer, 0);
        

        【讨论】:

          【解决方案8】:

          另一个答案是RNGCryptoServiceProvider 而不是Random。在这里您可以看到如何删除 MSB,因此结果始终为正。

          public static Int64 NextInt64()
          {
              var buffer = new byte[8];
              new RNGCryptoServiceProvider().GetBytes(buffer);
              return BitConverter.ToInt64(buffer, 0) & 0x7FFFFFFFFFFFFFFF;
          }
          

          【讨论】:

            【解决方案9】:
            Random r=new Random();
            int j=r.next(1,23);
            Console.WriteLine(j);
            

            【讨论】:

            • 随机类用于随机选择值。随机类为用户提供良好的环境
            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2019-05-15
            • 1970-01-01
            • 1970-01-01
            • 2018-03-10
            • 1970-01-01
            相关资源
            最近更新 更多