Нередко в своих программах нам приходится использовать генератор псевдослучайных чисел, или, как его еще называют, Random. С его помощью мы можем получать псевдослучайные числа, распределенные по равномерному закону. Иными словами, вероятности появления всех чисел одинаковы. Однако не всегда это удобно, и порой датчик, который мог бы генерировать числа как-то иначе, просто необходим, так что сейчас мы будем разбираться, как реализовать подобную штуку.
План действий
Первым делом нам нужно выбрать функцию плотности вероятности. Эта функция должна удовлетворять двум условиям:
- На заданном нами отрезке [a; b] функция должна быть положительной.
- Площадь под функцией на этом отрезке должна равняться единице.
В общем, все просто. Берем любую функцию, строим ее график и выбираем отрезок, на котором функция принимает положительные значения. Но тут может возникнуть проблема: площадь под выбранной функцией не равна единице. Чтобы это исправить, воспользуемся тем, что интересующая нас площадь ? есть площадь криволинейной трапеции, а она, в свою очередь, находится по формуле: Таким образом, найдя значение интеграла и разделив на него нашу функцию, мы получим новую функцию fk, которая будет удовлетворять всем нашим условиям. Теперь для получения одной случайной величины, нужно всего-навсего найти корень следующего уравнения, который и будет являться искомой величиной:
#image.jpgЗдесь V — случайная величина, равномерно распределенная на отрезке [0; 1], то есть величина, получаемая с помощью стандартного генератора псевдослучайных чисел.
Программная реализация
Создаем класс MyRandom, который будет наследоваться от стандартного класса Random.
Здесь func — функция, возвращающее значение левой части уже упомянутого выше уравнения:#image.jpg
Теперь осталось за малым, а именно переопределить все методы родительского класса.
На этом все. Единственное, на что следует обратить внимание, так это на следующее примечание с сайта msdn.microsoft.com:
Примечания для наследующих объектов
Начиная с платформы .NET Framework версии 2.0, при создании класса, производного от класса Random, и переопределении метода Sample распределение, предоставленное реализацией метода Sample в производном классе, не используется для вызова реализации следующих методов в базовом классе:
- Метод Random.NextBytes(Byte[]).
- Метод Random.Next().
- Метод Random.Next(Int32, Int32), если (maxValue. — minValue) больше Int32.MaxValue.
Вместо них используется равномерное распределение, предоставляемое базовым классом Random. Такой принцип действия повышает общую производительность класса Random. Чтобы изменить данный принцип для вызова реализации метода Sample в производном классе, необходимо также переопределить принцип действия этих трех членов.