none
Проблема со случайной величиной C# RRS feed

  • Вопрос

  • Решаю задачку, в которой необходимо много раз вызывать случайную величину x. Для этого написал следующую функцию:

     

    public double t(double M)
    {
    Random x = new Random();
    return (-1) * M * Math.Log(1 - x.NextDouble());
    }
    

    При этом 9 из десяти раз возвращается одно и то же "случайное" число.

    Выкручиваюсь следующим образом:

    public double t(double M)
        {
          Random x = new Random();
          int ran = 0;
          double y = new double();
          while (ran < 1000000)
          {
            ran++;
            y = x.NextDouble();
          }
          
          return (-1) * M * Math.Log(1 - y);
        }
    

    Этого миллиона как раз хватает. В чём проблема?

    Visual Studio 2010 Pro (dream spark)

    .NET Fr 3.5

    C#

     


    igortiunov.ru
    1 декабря 2010 г. 21:07

Ответы

  • Дело в том, что Random генерирует псевдослучайные числа. Это псевдослучайная последовательность, которая каждый раз будет повторяться при одинаковом начальном элементе. Вот чтобы на первом элементе все последовательности отличались - надо в качестве параметра взять параметр который действительно является почти совсем случайным. Например, DateTime.Now.Milliseconds - то есть текущее время в милисекундах. Или можно DateTime.Now.Ticks.

    Таким образом вместо
    Random x = new Random();
    надо указать в качестве параметра конструктора метода Random()
    Random x = new Random(DateTime.Now.Milliseconds);

    В изначальном коде для генерации числа каждый раз создается новый объект, поэтому и получается каждый раз один и тот же первый элемент одинаковой последовательности.

    • Предложено в качестве ответа PetrishkoMVP, Editor 1 декабря 2010 г. 22:10
    • Помечено в качестве ответа ITD27M01 2 декабря 2010 г. 6:26
    1 декабря 2010 г. 22:10
    Отвечающий
  • DateTime.Now.Ticks - это long

    DateTime.Now.Milliseconds - выдаст одинаковый рандом в пределах миллисекунды (огромный интервал, на самом деле).

    Стандартный конструктор рандома использует Enviroment.TickCount - легко проверить рефлектором:

    public Random() : this(Environment.TickCount)
    {
    }
    
    Миллиона в примере выше хватает для задержки, после которой Enviroment.TickCount изменяется, и свежесозданный объект Random получает другое начальне значение.

    Проще всего решить проблему используя один и тот же экземпляр Random для всех вызовов t() - сделай его полем класса, и создавай один раз, а не на каждый вызов t(). 


    • Помечено в качестве ответа ITD27M01 2 декабря 2010 г. 6:26
    1 декабря 2010 г. 23:30

Все ответы

  • Дело в том, что Random генерирует псевдослучайные числа. Это псевдослучайная последовательность, которая каждый раз будет повторяться при одинаковом начальном элементе. Вот чтобы на первом элементе все последовательности отличались - надо в качестве параметра взять параметр который действительно является почти совсем случайным. Например, DateTime.Now.Milliseconds - то есть текущее время в милисекундах. Или можно DateTime.Now.Ticks.

    Таким образом вместо
    Random x = new Random();
    надо указать в качестве параметра конструктора метода Random()
    Random x = new Random(DateTime.Now.Milliseconds);

    В изначальном коде для генерации числа каждый раз создается новый объект, поэтому и получается каждый раз один и тот же первый элемент одинаковой последовательности.

    • Предложено в качестве ответа PetrishkoMVP, Editor 1 декабря 2010 г. 22:10
    • Помечено в качестве ответа ITD27M01 2 декабря 2010 г. 6:26
    1 декабря 2010 г. 22:10
    Отвечающий
  • DateTime.Now.Ticks - это long

    DateTime.Now.Milliseconds - выдаст одинаковый рандом в пределах миллисекунды (огромный интервал, на самом деле).

    Стандартный конструктор рандома использует Enviroment.TickCount - легко проверить рефлектором:

    public Random() : this(Environment.TickCount)
    {
    }
    
    Миллиона в примере выше хватает для задержки, после которой Enviroment.TickCount изменяется, и свежесозданный объект Random получает другое начальне значение.

    Проще всего решить проблему используя один и тот же экземпляр Random для всех вызовов t() - сделай его полем класса, и создавай один раз, а не на каждый вызов t(). 


    • Помечено в качестве ответа ITD27M01 2 декабря 2010 г. 6:26
    1 декабря 2010 г. 23:30
  • О, отлично, спасибо! На четвёртом пентиуме этот миллион заметен весьма!
    igortiunov.ru
    2 декабря 2010 г. 6:26