
6. Программирование датчика случайных чисел
Запрограммируем датчик случайных чисел для нормального распределения по методу «Преобразование Бокса – Мюллера». Этот точный метод используется для моделирования стандартных нормально распределённых случайных величин.
Метод «Преобразование Бокса – Мюллера»:
Пусть r и f – независимые случайные величины, равномерно распределённые на интервале (0, 1]. Вычислим z0 и z1 по формулам:
,
.
Тогда z0 и z1 будут независимы и распределены нормально с математическим ожиданием 0 и дисперсией 1.
После получения стандартной нормальной случайной величины z, можно легко перейти к величине ξ=N(μ,σ2), распределённой нормально с математическим ожиданием μ и стандартным отклонением σ по формуле:
ξ = μ + σz.
Это уже не является частью преобразования Бокса – Мюллера, но позволяет завершить генерацию нормальной случайной величины.
Рис. 6 – Гистограмма сгенерированных значений.
7. Код программы с комментариями
Программа на языке C#:
using System;
using System.IO;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Lab_0
{
class Program
{
static void Main(string[] args)
{
#region чтение из файла
StreamReader streamReader = new StreamReader("v16.txt");
string str = "";
while (!streamReader.EndOfStream)
{
str += streamReader.ReadLine() + '&';
}
str = str.Replace('.', ',');
StringBuilder builder = new StringBuilder(str);
builder[str.Length-1] = '0';
str = builder.ToString();
string [] sNumbers = str.Split('&');
//массив чисел
double [] dNumbers = new double[sNumbers.Length];
for (int i = 0; i < sNumbers.Length; i++)
{
dNumbers[i] = double.Parse(sNumbers[i]);
}
#endregion
#region бустреп-выборки
StreamWriter sw = new StreamWriter("res16.txt");
sw.WriteLine(".........Бутстреп - метод..........");
//число бутстреп-выборок
int numB = 1000;
Random randValue = new Random();
int min = (int) Math.Floor(dNumbers.Min())-1;
int max = (int) Math.Ceiling(dNumbers.Max());
double[,] dPInterval = new double[numB, max - min];
double[] dInterv = new double[max - min];
double[] a = new double[numB];
double[] dValues = new double[dNumbers.Length];
double[] disp = new double[numB];
double sum, sumA, dispA;
sw.WriteLine(min + " " + max);
//цикл по числу бутстреп-выборок
sumA = 0;
dispA = 0;
for (int i = 0; i < numB; i++)
{
sum = 0;
for (int j = 0; j < dNumbers.Length; j++)
{
dValues[j] = dNumbers[(int)Math.Round((double)randValue.NextDouble()*(dNumbers.Length-1))];
sum += dValues[j];
//определение попадания в интервал
dPInterval[i, (int) Math.Floor(dValues[j] - min)]++;
}
for (int j = 0; j < max - min; j++)
{
dPInterval[i, j] /= dNumbers.Length;
}
a[i] = sum / dNumbers.Length;
//мат.ожидание
sumA += a[i];
sum = 0;
for (int j = 0; j < dNumbers.Length; j++)
{
sum += Math.Pow(dValues[j], 2);
}
disp[i] = (sum / dNumbers.Length) - Math.Pow(a[i], 2);
//дисперсия
dispA += disp[i];
}
dispA /= numB;
sumA /= numB;
sw.WriteLine("---------------------------------");
for (int i = 0; i < max-min; i++)
{
for (int j = 0; j < numB; j++)
{
dInterv[i] += dPInterval[j, i];
}
dInterv[i] /= numB;
sw.WriteLine(dInterv[i]);
}
sw.WriteLine("Мат.ожидание: " + sumA + " Дисперсия:" + dispA);
#endregion
#region генератор
sw.WriteLine("-------Генератор--------");
double z=0;
double[] dInterval = new double[max - min];
for (int i = 0; i < numB*100000; i++)
{
//z-случайное значение по нормальному закону распределения
z = sumA + Math.Sqrt(dispA) * (Math.Cos(2 * Math.PI * randValue.NextDouble()) * Math.Sqrt(-2 * Math.Log(randValue.NextDouble())));
if(z>min && z<max)
dInterval[(int)Math.Floor(z - min)]++;
}
for (int i = 0; i < max - min; i++)
{
dInterval[i] /= numB * 100000;
sw.WriteLine(dInterval[i]);
}
sw.Close();
#endregion
//Console.ReadLine();
}
}
}