[Алгоритмы, Математика] Программный генератор статистически безупречных случайных чисел
Автор
Сообщение
news_bot ®
Стаж: 6 лет 9 месяцев
Сообщений: 27286
Программный генератор статистически безупречных случайных чисел
Проблема создания таких программ широко обсуждалась в математической литературе в 1965-1975 годах,
тогда же отмечалась сложность этой задачи.
Современная математика имеет значительные достижения в этом вопросе.
Они доступны узким специалистам, но сложны для понимания, и удалились из широкого обсуждения.
Я предлагаю здесь простое решение этой задачи, оно, возможно, недостойно внимания больших математиков, но вполне доступно начинающим.
Мне удалось создать программу, генерирующую последовательность символов '0' и '1', имеющую безупречно хорошие статистические свойства.
Конструкция программы проста и легко доступна для понимания.
Случайная последовательность нулей и единиц должна обладать следующими свойствами:
- количество нулей и единиц во всех фрагментах этой последовательности примерно одинаково;
- количество вхождений фрагментов 00, 01, 10 и 11 всегда примерно одинаково;
- то же касается всевозможных фрагментов длины 3, 4, 5 и так далее.
Ясно, что программа может подсчитывать количество вхождений таких фрагментов в уже сформированную последовательность и генерировать очередной символ так, чтобы поддерживать перечисленные равенства.
Если анализировать эти равенства в порядке возрастания длины фрагмента, то программа быстро зацикливается.
Однако, если их анализировать в обратном порядке, то всё получается замечательно хорошо.
Что же в итоге получилось?
Задаётся некоторая начальная последовательность символов '0' и '1' (начальный отрезок), которую программа будет достраивать до заранее заданной предельной длины, после чего остановится.
Такая организация программы целесообразна в связи с тем, что по мере роста длины сформированной последовательности скорость формирования очередного символа уменьшается.
Для формирования очередного символа программа организует цикл, по различным длинам маски (идентификатор lenmask).
Маска в этом цикле задаётся как фрагмент сформированной последовательности, состоящий из lenmask её последних символов.
Такая маска циклически передвигается вдоль сформированной последовательности.
В ходе этого вложенного цикла передвижений подсчитываются суммы s0 и s1, это количество появлений нуля или соответственно единицы в сформированной последовательности непосредственно после обнаруженного совпадения маски с ней.
Если по окончании подсчёта при очередной заданной длине маски значения s0 и s1 оказываются различными, то при s0>s1 очередной символ формируется как 1, иначе как 0 и цикл по длинам масок прерывается.
Если же при всех длинах маски значения сумм s0 и s1 окажутся одинаковыми, то очередной символ сформируется по значению резервной переменной, принимающей одно из двух значений 0 или 1 и меняющей значение после каждого использования.
Эта ситуация, конечно, маловероятна.
Математически строгое доказательство того, что сформированная описанной программой последовательность нулей и единиц обладает необходимыми статистическими свойствами, остаётся нерешённой трудной задачей, однако непосредственный контроль пробных запусков этой программы принёс очень хорошие результаты.
Детально комментированный текст этой программы на языке JAVA представлен в приложении.
Программа состоит из двух частей.
Это собственно формирование псевдослучайной последовательности и статистический контроль результата.
Для контроля формируется некоторое количество масок различной длины.
Эти маски наполнены нулями и единицами.
Подсчитывается количество вхождений этих масок в сформированную последовательность.
Как и следовало ожидать, результаты контроля демонстрируют, что количество таких вхождений зависит от длины маски и почти не зависит от её наполнения.
Удивительно, что такая вполне элементарная программа позволяет получить результат, казавшийся недостижимым простыми средствами.
Приложение
Текст программы на языке JAVA
//gerase = generator random sequence
//генератор статистически безупречной
//случайной последовательности нулей и единиц
package ikojar;
public class gerase {
public static void main(String[] args) {
//управляющие параметры программы
//число, кодирующее начальный отрезок формируемой последовательности
//двоичное представление числа beg станет
//началом формируемой последовательности
int beg=5,
//длина формируемой последовательности
lenrez=2048,
//maxpower это максимальная длина контрольной маски
//в процессе статистического контроля сформированной последовательности
//контрольная маска скользящим образом
//накладывается на сформированную последовательность
//подсчитывается количество вхождений
//различных вариантов наполнения маски
//для разных вариантов наполнения маски
//количество её вхождений в сформированную последовательность
//должно быть приблизительно одинаковым
maxpower=10;
//декларация рабочих переменных программы
//rs это random symbol, может быть использован,
//если очередной символ не был определён алгоритмом формирования
//алгоритм не сможет сформировать очередной символ, если
//в результате расчёта окажется, что и нуль и единица одинаково допустимы
byte rs=0;
//массив result будет содержать сформированную последовательность
//нулей и единиц
byte[] result=new byte[lenrez];
//массив mask будет вместилищем контрольной маски, используемой
//как при формировании последовательности,
//так и при её статистическом контроле
//длина маски будет изменяться внутри программы,
//здесь просто резервируется максимально необходимое место для неё
byte[] mask=new byte[lenrez];
//собственно формирование псевдослучайной последовательности
//распаковка управляющего числа beg
//двоичное представление управляющего числа beg будет помещено
//в начало формируемой псевдослучайной последовательности result
int p=beg,bp=0;
for(;;)
{//cir raspak
result[bp]=(byte)(p%2);
bp++;
if(p<2)break;
p/=2;
}//cir raspak
//печать начального отрезка
String so="начальный фрагмент ";
for(int i=0;i<bp;i++)so+=String.valueOf(result[i]);
System.out.println(so);
//подготовка печати результата
System.out.println("сформирована последовательность");
//цикл формирования выходной последовательности
for(int pos=bp;pos<lenrez;pos++)
{//circlepos
//признак hs(hard symbol) это
//признак того, что очередной символ формируемой выходной
//последовательности определился в результате расчёта
//если расчёт не сможет определить очередной символ,
//то он будет задан из переменной rs
int hs=0;
//цикл по убывающему размеру маски
//lenmask это длина маски
for(int lenmask=pos-2;lenmask>=0;lenmask--)
{//lenmask
//заполнение маски последними символами
//ранее сформированной последовательности
for(int i=0;i<lenmask;i++)mask[i]=result[pos+i-lenmask];
//s0 и s1 станут результатами подсчёта
//количества вхождений нулей и единиц соответственно
//непосредственно после очередного вхождения образа маски
//в уже сформированную последовательность
//при скользящем наложении маски на эту последовательность
int s0=0,s1=0;
//цикл скользящего продвижения маски вдоль
//сформированной последовательности псевдослучайных символов
for(int i=lenmask;i<pos;i++)
{//calcS01
//eqm это признак совпадения фрагмента
//сформированной последовательности с наложенной маской
int eqm=1;
//вычисление eqm
for(int i1=0;i1<lenmask;i1++)if(mask[i1]!=result[i+i1-lenmask]){eqm=0;break;}
//собственно акт подсчёта количества нулей или единиц, следующих
//непосредственно после вхождения образа маски
if(eqm==1)if(result[i]==0)s0++;else s1++;
}//calcS01
//формирование очередного символа выходной последовательности
//в зависимости от соотношения между s0 и s1
//признак hs станет равным 1, если
//таким образом будет сформирован очередной символ
if(s0<s1){result[pos]=0;hs=1;break;}
if(s1<s0){result[pos]=1;hs=1;break;}
}//lenmask
if(hs==1)continue;
//если расчёт не определил очередной символ,
//то он формируется из переменной rs
result[pos]=rs;rs=(byte)(1-rs);
}//circlepos
//выходная последовательность готова
//осталось выдать её на печать
so="";
for(int i=0,c=0;i<lenrez;i++)
{//out rez
so+=String.valueOf(result[i]);
c++;
if(c==64){c=0;System.out.println(so);so="";}
}//out rez
System.out.println(so);
//а теперь статистический анализ сформированной последовательности
System.out.println
("статистический анализ сформированной последовательности");
//цикл по различным размерам контрольных масок
//pw это длина контрольной маски,
//накладываемой на сформированную последовательность
for(int pw=1;pw<maxpower;pw++)
{//pw
//контрольные маски будут наполняться
//всевозможными комбинациями нулей и единиц
//эти комбинации можно интерпретировать как двоичные представления
//того или иного неотрицательного целого числа
//будут перебираться все
//такие представляющие числа в пределах от 0 до pm-1
//верхняя граница pm для такого перебора сейчас будет определена
int pm=1;for(int i=0;i<pw;i++)pm*=2;
//печатаем заголовок серии чисел, равных количеству вхождений
//очередной маски в сформированную последовательность
System.out.println("для маски длиной "+String.valueOf(pw));
int mincount=lenrez,maxcount=0;
//цикл последовательного перебора целых чисел от 0 до pm-1,
//двоичное представление которых станет содержимым очередной маски
for(int im=0;im<pm;im++)
{//im
//заполнение маски двоичным представлением числа im
p=im;
for(int i=pw-1;i>=0;i--)
{mask[i]=(byte)(p%2);p/=2;}
//цикл скользящего наложения контрольной маски
//на сформированную последовательность
//переменная s станет равной количеству совпадений
//контрольной маски с сформированной последовательностью
int s=0;
for(int i0=pw;i0<=lenrez;i0++)
{//i0
//проверка совпадения маски с содержимым под маской
int eqm=1;
for(int i1=0;i1<pw;i1++)if(result[i0+i1-pw]!=mask[i1]){eqm=0;break;}
if(eqm==1)s++;
}//i0
//печатаем очередное число вхождений
//маски в сформированную последовательность
//этот громоздкий вариант печати здесь дезактивирован
//System.out.println(String.valueOf(s));
//подготовка укороченных оценок качества результата
if(s<mincount)mincount=s;
if(s>maxcount)maxcount=s;
}//im
System.out.println("минимум вхождений="+String.valueOf(mincount));
System.out.println("максимум вхождений="+String.valueOf(maxcount));
}//pw
return;
}//main
}//class
===========
Источник:
habr.com
===========
Похожие новости:
- [Алгоритмы, Программирование микроконтроллеров, Производство и разработка электроники] Бинарный поиск в микроконтроллере
- [Алгоритмы, Профессиональная литература] Книга «Совершенный алгоритм. Алгоритмы для NP-трудных задач »
- [Алгоритмы, Машинное обучение, Исследования и прогнозы в IT, Искусственный интеллект] Исследователи изучают, как GPT-3 разбирает входящую почту
- [Математика] Новые квантовые алгоритмы, совершившие прорыв в нелинейных уравнениях (перевод)
- [Программирование, Алгоритмы, Go] Algorithms in Go: Dutch National Flag
- [Алгоритмы, Сжатие данных, Мониторы и ТВ, Электроника для начинающих] Что такое HDR10+? Разбор
- [Алгоритмы, Машинное обучение, История IT] Рекомендательный движок за 2 строчки кода
- [Программирование, C++, Алгоритмы, Математика] Пишем свой парсер математических выражений и калькулятор командной строки (перевод)
- [Алгоритмы, Математика, Научно-популярное] Математик-пенсионер, «хакнувший» лотерею
- [Программирование, Алгоритмы, Программирование микроконтроллеров, Бизнес-модели, Визуальное программирование] Умеет ли человечество писать алгоритмы? Безошибочные алгоритмы и язык ДРАКОН. Сенатор: они находились в летающих гробах
Теги для поиска: #_algoritmy (Алгоритмы), #_matematika (Математика), #_programma (программа), #_prostoj (простой), #_psevdosluchajnyj (псевдослучайный), #_bezuprechnyj (безупречный), #_algoritmy (
Алгоритмы
), #_matematika (
Математика
)
Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Текущее время: 23-Ноя 03:28
Часовой пояс: UTC + 5
Автор | Сообщение |
---|---|
news_bot ®
Стаж: 6 лет 9 месяцев |
|
Программный генератор статистически безупречных случайных чисел Проблема создания таких программ широко обсуждалась в математической литературе в 1965-1975 годах, тогда же отмечалась сложность этой задачи. Современная математика имеет значительные достижения в этом вопросе. Они доступны узким специалистам, но сложны для понимания, и удалились из широкого обсуждения. Я предлагаю здесь простое решение этой задачи, оно, возможно, недостойно внимания больших математиков, но вполне доступно начинающим. Мне удалось создать программу, генерирующую последовательность символов '0' и '1', имеющую безупречно хорошие статистические свойства. Конструкция программы проста и легко доступна для понимания. Случайная последовательность нулей и единиц должна обладать следующими свойствами:
Что же в итоге получилось? Задаётся некоторая начальная последовательность символов '0' и '1' (начальный отрезок), которую программа будет достраивать до заранее заданной предельной длины, после чего остановится. Такая организация программы целесообразна в связи с тем, что по мере роста длины сформированной последовательности скорость формирования очередного символа уменьшается. Для формирования очередного символа программа организует цикл, по различным длинам маски (идентификатор lenmask). Маска в этом цикле задаётся как фрагмент сформированной последовательности, состоящий из lenmask её последних символов. Такая маска циклически передвигается вдоль сформированной последовательности. В ходе этого вложенного цикла передвижений подсчитываются суммы s0 и s1, это количество появлений нуля или соответственно единицы в сформированной последовательности непосредственно после обнаруженного совпадения маски с ней. Если по окончании подсчёта при очередной заданной длине маски значения s0 и s1 оказываются различными, то при s0>s1 очередной символ формируется как 1, иначе как 0 и цикл по длинам масок прерывается. Если же при всех длинах маски значения сумм s0 и s1 окажутся одинаковыми, то очередной символ сформируется по значению резервной переменной, принимающей одно из двух значений 0 или 1 и меняющей значение после каждого использования. Эта ситуация, конечно, маловероятна. Математически строгое доказательство того, что сформированная описанной программой последовательность нулей и единиц обладает необходимыми статистическими свойствами, остаётся нерешённой трудной задачей, однако непосредственный контроль пробных запусков этой программы принёс очень хорошие результаты. Детально комментированный текст этой программы на языке JAVA представлен в приложении. Программа состоит из двух частей. Это собственно формирование псевдослучайной последовательности и статистический контроль результата. Для контроля формируется некоторое количество масок различной длины. Эти маски наполнены нулями и единицами. Подсчитывается количество вхождений этих масок в сформированную последовательность. Как и следовало ожидать, результаты контроля демонстрируют, что количество таких вхождений зависит от длины маски и почти не зависит от её наполнения. Удивительно, что такая вполне элементарная программа позволяет получить результат, казавшийся недостижимым простыми средствами. Приложение Текст программы на языке JAVA //gerase = generator random sequence
//генератор статистически безупречной //случайной последовательности нулей и единиц package ikojar; public class gerase { public static void main(String[] args) { //управляющие параметры программы //число, кодирующее начальный отрезок формируемой последовательности //двоичное представление числа beg станет //началом формируемой последовательности int beg=5, //длина формируемой последовательности lenrez=2048, //maxpower это максимальная длина контрольной маски //в процессе статистического контроля сформированной последовательности //контрольная маска скользящим образом //накладывается на сформированную последовательность //подсчитывается количество вхождений //различных вариантов наполнения маски //для разных вариантов наполнения маски //количество её вхождений в сформированную последовательность //должно быть приблизительно одинаковым maxpower=10; //декларация рабочих переменных программы //rs это random symbol, может быть использован, //если очередной символ не был определён алгоритмом формирования //алгоритм не сможет сформировать очередной символ, если //в результате расчёта окажется, что и нуль и единица одинаково допустимы byte rs=0; //массив result будет содержать сформированную последовательность //нулей и единиц byte[] result=new byte[lenrez]; //массив mask будет вместилищем контрольной маски, используемой //как при формировании последовательности, //так и при её статистическом контроле //длина маски будет изменяться внутри программы, //здесь просто резервируется максимально необходимое место для неё byte[] mask=new byte[lenrez]; //собственно формирование псевдослучайной последовательности //распаковка управляющего числа beg //двоичное представление управляющего числа beg будет помещено //в начало формируемой псевдослучайной последовательности result int p=beg,bp=0; for(;;) {//cir raspak result[bp]=(byte)(p%2); bp++; if(p<2)break; p/=2; }//cir raspak //печать начального отрезка String so="начальный фрагмент "; for(int i=0;i<bp;i++)so+=String.valueOf(result[i]); System.out.println(so); //подготовка печати результата System.out.println("сформирована последовательность"); //цикл формирования выходной последовательности for(int pos=bp;pos<lenrez;pos++) {//circlepos //признак hs(hard symbol) это //признак того, что очередной символ формируемой выходной //последовательности определился в результате расчёта //если расчёт не сможет определить очередной символ, //то он будет задан из переменной rs int hs=0; //цикл по убывающему размеру маски //lenmask это длина маски for(int lenmask=pos-2;lenmask>=0;lenmask--) {//lenmask //заполнение маски последними символами //ранее сформированной последовательности for(int i=0;i<lenmask;i++)mask[i]=result[pos+i-lenmask]; //s0 и s1 станут результатами подсчёта //количества вхождений нулей и единиц соответственно //непосредственно после очередного вхождения образа маски //в уже сформированную последовательность //при скользящем наложении маски на эту последовательность int s0=0,s1=0; //цикл скользящего продвижения маски вдоль //сформированной последовательности псевдослучайных символов for(int i=lenmask;i<pos;i++) {//calcS01 //eqm это признак совпадения фрагмента //сформированной последовательности с наложенной маской int eqm=1; //вычисление eqm for(int i1=0;i1<lenmask;i1++)if(mask[i1]!=result[i+i1-lenmask]){eqm=0;break;} //собственно акт подсчёта количества нулей или единиц, следующих //непосредственно после вхождения образа маски if(eqm==1)if(result[i]==0)s0++;else s1++; }//calcS01 //формирование очередного символа выходной последовательности //в зависимости от соотношения между s0 и s1 //признак hs станет равным 1, если //таким образом будет сформирован очередной символ if(s0<s1){result[pos]=0;hs=1;break;} if(s1<s0){result[pos]=1;hs=1;break;} }//lenmask if(hs==1)continue; //если расчёт не определил очередной символ, //то он формируется из переменной rs result[pos]=rs;rs=(byte)(1-rs); }//circlepos //выходная последовательность готова //осталось выдать её на печать so=""; for(int i=0,c=0;i<lenrez;i++) {//out rez so+=String.valueOf(result[i]); c++; if(c==64){c=0;System.out.println(so);so="";} }//out rez System.out.println(so); //а теперь статистический анализ сформированной последовательности System.out.println ("статистический анализ сформированной последовательности"); //цикл по различным размерам контрольных масок //pw это длина контрольной маски, //накладываемой на сформированную последовательность for(int pw=1;pw<maxpower;pw++) {//pw //контрольные маски будут наполняться //всевозможными комбинациями нулей и единиц //эти комбинации можно интерпретировать как двоичные представления //того или иного неотрицательного целого числа //будут перебираться все //такие представляющие числа в пределах от 0 до pm-1 //верхняя граница pm для такого перебора сейчас будет определена int pm=1;for(int i=0;i<pw;i++)pm*=2; //печатаем заголовок серии чисел, равных количеству вхождений //очередной маски в сформированную последовательность System.out.println("для маски длиной "+String.valueOf(pw)); int mincount=lenrez,maxcount=0; //цикл последовательного перебора целых чисел от 0 до pm-1, //двоичное представление которых станет содержимым очередной маски for(int im=0;im<pm;im++) {//im //заполнение маски двоичным представлением числа im p=im; for(int i=pw-1;i>=0;i--) {mask[i]=(byte)(p%2);p/=2;} //цикл скользящего наложения контрольной маски //на сформированную последовательность //переменная s станет равной количеству совпадений //контрольной маски с сформированной последовательностью int s=0; for(int i0=pw;i0<=lenrez;i0++) {//i0 //проверка совпадения маски с содержимым под маской int eqm=1; for(int i1=0;i1<pw;i1++)if(result[i0+i1-pw]!=mask[i1]){eqm=0;break;} if(eqm==1)s++; }//i0 //печатаем очередное число вхождений //маски в сформированную последовательность //этот громоздкий вариант печати здесь дезактивирован //System.out.println(String.valueOf(s)); //подготовка укороченных оценок качества результата if(s<mincount)mincount=s; if(s>maxcount)maxcount=s; }//im System.out.println("минимум вхождений="+String.valueOf(mincount)); System.out.println("максимум вхождений="+String.valueOf(maxcount)); }//pw return; }//main }//class =========== Источник: habr.com =========== Похожие новости:
Алгоритмы ), #_matematika ( Математика ) |
|
Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Текущее время: 23-Ноя 03:28
Часовой пояс: UTC + 5