【问题标题】:Weird "Random" behaviour with Random [duplicate]随机的奇怪“随机”行为[重复]
【发布时间】:2013-08-26 16:19:48
【问题描述】:

再次,我在这里需要一些帮助,今天我正在做一个 c# 作业,基本上包括创建一个可以总结 2 次掷骰子结果的方法,到目前为止,太好了!,没有什么难的事。 .. 但是,当我运行我的代码时,会发生一些非常奇怪的事情,我会让我的代码和结果自己说话:

using System;

class Program
{

    public static String GetTimestamp()
    {
        DateTime saveNow = DateTime.Now;
        return saveNow.ToString("yyyyMMddHHmmssffff");
    }

    public static int ThrowDice()
    {
        int randVal1, randVal2;
        string TS1, TS2;

        Random rand = new Random();
        randVal1 = rand.Next(1,6);
        TS1 = GetTimestamp();
        randVal2 = rand.Next(1,6);
        TS2 = GetTimestamp();

        Console.WriteLine("Dice 1: \t" + randVal1 + ' ' + TS1);
        Console.WriteLine("Dice 2: \t" + randVal2 + ' ' + TS2);
        Console.WriteLine("-----------------");

        return randVal1 + randVal2;
    }

    static void Main()
    {
        for(int i = 1; i<=10;i++)
        {
            Console.WriteLine("Dice Roll #" + i);
            Console.WriteLine("Dice Sum:\t" + ThrowDice());
            Console.WriteLine();
        }
    }
}

现在,这是我运行它时得到的:

掷骰子#1

骰子 1:1 / 时间戳:201308260146259075

骰子 2:2 / 时间戳:201308260146259131

骰子总和:3


掷骰子#2

骰子 1:2 / 时间戳:201308260146259135

骰子 2:5 / 时间戳:201308260146259135

骰子总和:7


掷骰子#3

骰子 1:2 / 时间戳:201308260146259135

骰子 2:5 / 时间戳:201308260146259135

骰子总和:7


掷骰子#4

骰子 1:2 / 时间戳:201308260146259135

骰子 2:5 / 时间戳:201308260146259135

骰子总和:7


掷骰子#5

骰子 1:2 / 时间戳:201308260146259135

骰子 2:5 / 时间戳:201308260146259135

骰子总和:7


掷骰子#6

骰子 1:2 / 时间戳:201308260146259135

骰子 2:5 / 时间戳:201308260146259135

骰子总和:7


掷骰子#7

骰子 1:2 / 时间戳:201308260146259135

骰子 2:5 / 时间戳:201308260146259135

骰子总和:7


掷骰子#8

骰子 1:2 / 时间戳:201308260146259135

骰子 2:5 / 时间戳:201308260146259135

骰子总和:7


掷骰子#9

骰子 1:2 / 时间戳:201308260146259135

骰子 2:5 / 时间戳:201308260146259135

骰子总和:7


掷骰子 #10

骰子 1:2 / 时间戳:201308260146259135

骰子 2:5 / 时间戳:201308260146259135

骰子总和:7


-第一卷很完美

-掷 2/骰子 1...完美,

-掷 2/骰子 2...WTH???

这些结果真的很奇怪,我期望在每卷上得到不同的时间戳和不同的值。时间戳是我想出的一个主意来检查这些数字的生成时间,看起来两个“骰子”同时滚动,看起来“随机”使用时钟生成种子。

我什至尝试使用 DiceRoll() 方法为骰子创建一个完整的类,但即使在两个完全不同的对象那里我只是一遍又一遍地得到相同的结果..

我该如何解决这个问题?有什么想法吗?

【问题讨论】:

  • 几乎每天都有人问这个问题。 API 设计者注意:这种设计是一个制造混乱的机器!
  • @EricLippert 那么您将如何设计 API?你会用不同的东西作为种子吗?强制用户始终提供自己的种子?有一个静态的“默认”Random 实例用于“正常”使用(不禁止创建其他实例)?
  • @Servy:这是个好问题;在 500 个字符的评论中很难详细说明每种方法的所有优缺点。 :-) 我的倾向是在第一个new Random 上播种当前时间,然后保持一个线程安全计数器,在每个后续new Random 上增加一个种子。这为您提供了合理的熵来源,并保证任何两个实例都有不同的种子,而不会产生巨大的性能成本。
  • @EricLippert 在这种情况下实际上会导致非随机行为。如果您从每个后续种子中获取第一个值,Random 不会保留其随机外观。

标签: c# datetime random timestamp


【解决方案1】:

Random,当与默认构造函数一起使用时,使用时间作为种子。使用相同的种子,您每次都会得到相同的结果。由于您连续多次创建新的Random,因此每个都将从相同的种子开始,因此产生相同的数字。要解决此问题,请仅制作一个 Random 并重复使用它。

此外,您可能很清楚这一点,但由于这是一个常见错误,而且大多数骰子掷骰都是从 1 到 6,我觉得我应该指出 Random.Next 使用和 独家 上绑定,所以目前你只能得到 1-5 的数字。

【讨论】:

  • 请注意Random 不是线程安全的,因此如果您有一个多线程程序,请非常小心在多个线程上重复使用相同的Random。在这种情况下,线程静态字段是个好主意。
  • Eric,感谢您对线程安全的警告! :) 知道这是件好事!
  • 迈克,我刚刚做了“静态随机 rand = new Random();”解决方案,它工作得很好!关于你在正确的地方......纠正它,现在我得到 6 个
【解决方案2】:

将 Rand 声明为静态变量并只初始化一次

using System;

class Program
{

    public static String GetTimestamp()
    {
        DateTime saveNow = DateTime.Now;
        return saveNow.ToString("yyyyMMddHHmmssffff");
    }

    public static int ThrowDice()
    {
        int randVal1, randVal2;
        string TS1, TS2;


        randVal1 = rand.Next(1,7);
        TS1 = GetTimestamp();
        randVal2 = rand.Next(1,7);
        TS2 = GetTimestamp();

        Console.WriteLine("Dice 1: \t" + randVal1 + ' ' + TS1);
        Console.WriteLine("Dice 2: \t" + randVal2 + ' ' + TS2);
        Console.WriteLine("-----------------");

        return randVal1 + randVal2;
    }
    static Random rand ;

    static void Main()
    {
        rand = new Random();

        for(int i = 1; i<=10;i++)
        {
            Console.WriteLine("Dice Roll #" + i);
            Console.WriteLine("Dice Sum:\t" + ThrowDice());
            Console.WriteLine();
        }
    }
}

并且时间戳可以在少数几卷中相同,但对于那么多的时间戳则不同

【讨论】:

  • 但仅在运行单线程时。
  • 嗯..是的..时间戳很奇怪,因为我是用来调试代码的,这并不重要,但我很想了解这里发生了什么,所以我可以重用未来的代码。
猜你喜欢
  • 1970-01-01
  • 2012-05-28
  • 2013-04-03
  • 2017-03-29
  • 2018-05-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多