Страницы: 1
RSS
линейный конгруэнтный метод - выработка псевдосл. чисел
 
Уважаемые форумчане, здравствуйте! Помогите, пожалуйста, разобраться, почему при реализации линейного конгруэнтного метода выдается ошибка Run-time error '6' overflow - empty - пустое выражение (0). Прим. смотреть макрос :)  
Спасибо!
 
Какая прелесть, Высшая математика. Чтобы Вам помочь нужно долго споминать, что такое конгруэнтный метод.  
 
Касательно ошибки Run-time error '6' overflow - empty. То это ошибка возникает когда у Вас произходит переполнение. Или выход за границы диапазона. Полагаю Вам необходимо пересмотреть цикл и зделать ограничение по числу итераций.
 
а мне кажется там какое то ограничение с функцией mod.  
 
попробуйте так записать  
ran(l + 1) = (a1 * ran(l) + c) / m - Round(((a1 * ran(l) + c) / m), 0)
 
Dophin, VovaK спасибо!  
Dophin, действительно, в mod загвоздка, осталось ее найти :)  
С Вашей формулой работает, разбираю, как Вы это сделали :)
 
Dophin, Вы до этой формулы сами дошли? Может быть, на книгу какую опирались? Ткните мне, пожалуйста, где об этом можно прочитать )  
Спасибо.
 
считает то считает, да неправильно  
 
99/10 - round(99/10,0) = -0,1  
 
ran(l + 1) = (a1 * ran(l) + c) / m - WorksheetFunction.Floor(((a1 * ran(l) + c) / m), 1)  
 
так правильнее  
 
дошел сам, на лыжах))
 
Лыжи-то хороши, но иногда могут не туда довести :-)  
Определим остаток от деления небольших числах, например, 190 на 6:  
1) 190 Mod 6 = 4  
2) 190 / 6 - WorksheetFunction.Floor(190 / 6, 1) = 0.666666666666667  
 
А проблема действительно в операторе MOD, который в VBA работает с числами в диапазоне Long-типа от -2147483,648 до 2147483647  
Поэтому, например, 3000000000 MOD 2 выдаст ошибку переполнения (overflow)  
 
Между прочим, аналогичная функция ячеек =ОСТАТ()  работает со всем допустимым для Excel диапазоном чисел без переполнения.  
 
Для работы в VBA со всем допустимым для Excel диапазоном чисел можно, например,  создать такую пользовательскую функцию:  
 
' ZVI: ModBig(Num1, Num2) аналогично Num1 Mod Num2  
' но работает со всем диапазоном чисел  
Function ModBig(Num1, Num2) As Double  
 ModBig = CDbl(Evaluate("=MOD(" & Num1 & "," & Num2 & ")"))  
End Function  
 
Вызов этой функции из кода: ran(l + 1) = ModBig(a1 * ran(l) + c, m)
 
Блин, вот о чём тема?  
Я ни фига не понял...  
Надоело себя тупым чувствовать...  
Может темы по ВБА, отдельно пускать?
 
Серж айда к нам в удивительную страну VBA. Только поначалу страшно, а потом будешь читать код как грамоту.
 
ага) а у Уокенбаха целая глава посвящена управлению сводными таблицами с помощью ВБА ))
 
прокомментируйте пожалуйста кто нибудь строчку    
 
ModBig = CDbl(Evaluate("=MOD(" & Num1 & "," & Num2 & ")"))  
 
уже полчаса медитирую - непонятно как работает. какой древний рудимент аля ВЫЧИСЛИТЬ ?
 
:) буквально!
Живи и дай жить..
 
{quote}{login=Dophin}{date=17.02.2010 03:18}{thema=}{post}прокомментируйте пожалуйста кто нибудь строчку    
 
ModBig = CDbl(Evaluate("=MOD(" & Num1 & "," & Num2 & ")"))  
 
уже полчаса медитирую - непонятно как работает. какой древний рудимент аля ВЫЧИСЛИТЬ ?{/post}{/quote}Это аналог вычисления формулы ячейки =ОСТАТ(190;6)  
В VBA вызывается так: Evaluate("=MOD(190,6)")
 
Спасибо)
 
Ребята, огромное спасибо! Сижу, втыкаю :)
 
{quote}{login=ZVI}{date=17.02.2010 01:14}{thema=}{post}Лыжи-то хороши, но иногда могут не туда довести :-)  
Определим остаток от деления небольших числах, например, 190 на 6:  
1) 190 Mod 6 = 4  
2) 190 / 6 - WorksheetFunction.Floor(190 / 6, 1) = 0.666666666666667  
 
А проблема действительно в операторе MOD, который в VBA работает с числами в диапазоне Long-типа от -2147483,648 до 2147483647  
Поэтому, например, 3000000000 MOD 2 выдаст ошибку переполнения (overflow)  
 
Между прочим, аналогичная функция ячеек =ОСТАТ()  работает со всем допустимым для Excel диапазоном чисел без переполнения.  
 
Для работы в VBA со всем допустимым для Excel диапазоном чисел можно, например,  создать такую пользовательскую функцию:  
 
' ZVI: ModBig(Num1, Num2) аналогично Num1 Mod Num2  
' но работает со всем диапазоном чисел  
Function ModBig(Num1, Num2) As Double  
 ModBig = CDbl(Evaluate("=MOD(" & Num1 & "," & Num2 & ")"))  
End Function  
 
Вызов этой функции из кода: ran(l + 1) = ModBig(a1 * ran(l) + c, m){/post}{/quote}  
 
А при фиксированной константе m=2^32=4294967296    
ran(l + 1) = (a1 * ran(l) + c) / m - WorksheetFunction.Floor(((a1 * ran(l) + c) / m), 1)    
тоже дает неверные результаты? 'остаток от деления на небольшие числа' ?
 
{quote}{login=}{date=17.02.2010 08:26}{thema=Re: }{post}А при фиксированной константе m=2^32=4294967296    
ran(l + 1) = (a1 * ran(l) + c) / m - WorksheetFunction.Floor(((a1 * ran(l) + c) / m), 1)    
тоже дает неверные результаты? 'остаток от деления на небольшие числа' ?{/post}{/quote}  
Да. Добавьте в цикл 2 строки для вывода отладочной информации:  
 
 While l < N2  
   'ran(l + 1) = (a1 * ran(l) + c) Mod m  
   Debug.Print 1, (a1*ran(l)+c)/m - WorksheetFunction.Floor(((a1*ran(l)+c)/m),1)  
   Debug.Print 2, ModBig(a1 * ran(l) + c, m)  
   ran(l + 1) = ModBig(a1 * ran(l) + c, m)  
   l = l + 1  
 Wend  
 
И, нажимая F8, сравните результат в окне Immediate.  
Для 3-х проходов по циклу получаем:  
1 0,256935039069504    
2 1103527590    
1 0,587870657444    
2 2015    
1 0,718314896337688    
2 3085138988    
 
где значения под индексом 1 - для (a1*ran(l)+c)/m - WorksheetFunction.Floor(((a1*ran(l)+c)/m),1)  
а под индексом 2 - для 2, ModBig(a1 * ran(l) + c, m)
 
ZVI, выражаю Вам огромную благодарность! ++++++
 
Ребят, я вас наверное достала уже( Дурак я, дурак..  
 
 
И, нажимая F8, сравните результат в окне Immediate.  
Для 3-х проходов по циклу получаем:  
1 0,256935039069504    
2 1103527590    
1 0,587870657444    
2 2015    
1 0,718314896337688    
2 3085138988    
 
где значения под индексом 1 - для (a1*ran(l)+c)/m - WorksheetFunction.Floor(((a1*ran(l)+c)/m),1)  
а под индексом 2 - для 2, ModBig(a1 * ran(l) + c, m)  
 
Но ведь должны получаться как раз-таки значения, равномерно распределенные на [0,1]? А в методе под индексом 2 почему такие огромные числа? Там ведь остаток от деления?
 
{quote}{login=kitikat}{date=10.03.2010 07:02}{thema=}{post}Но ведь должны получаться как раз-таки значения, равномерно распределенные на [0,1]? А в методе под индексом 2 почему такие огромные числа? Там ведь остаток от деления?{/post}{/quote} Потому что линейный конгруэнтный генератор псевдослучаных чисел выдает целые числа. А если нужно получать в диапазоне от нуля до единицы, то нужно делить значения на m.
 
Но почему бы тогда не использовать стандартную VBA-функцию генерации случайных чисел Rnd в паре с оператором Randomize, который задает случайное начальное значение для Rnd? Rnd имеет лучшие статистические параметры, чем та, что Вы пытаетесь использолвать. Разве что для обучения? Тогда привожу пример кода для такого генератора ПСП:  
 
' Линейный конгруэнтный генератор псевдослучаных чисел  
' От параметров зависит длина генерируемой последовательности.  
' A - множитель, должно выполняться условие: A mod 4 = 1  
' B - приращение, должно быть нечетным  
' M - модуль, обычно M=2^n где n - длина машинного слова в битах  
' Yo - исходное значение, которое может задаваться при 1-м вызове  
' Результат: Y1, Y2, ... , Yi, Yii где Yii = (A*Yi+B) Mod M  
Function RndCongruent(A, B, M, Optional Yo) As Double  
 Dim x#  
 Static Y#  
 If Not IsMissing(Yo) Then Y = Yo  
 x = A * Y + B  
 Y = CDbl(Evaluate("=MOD(" & x & "," & M & ")"))  
 RndCongruent = Y / M ' Если не делить на M, то выдаст целые числа  
End Function  
 
Sub Test()  
 Dim A, B, M, Yo  
 'A = 1103515245 ' <-- это плохой выбор, последовательноть - короче некуда  
 A = 100001  ' <-- а с этим значением длина последовательности длиннее  
 B = 123456789  
 M = 2 ^ 32  
 Yo = 1000  
 ' 1-й вызов, задаем Yo  
 RndCongruent A, B, M, Yo  
 ' Крутим дальше  
 For i = 1 To 20  
   Debug.Print i, RndCongruent(A, B, M)  
 Next  
End Sub
 
ZVI, спасибоо!!!! Вы в который раз меня выручаете. Вот я дурак, ModBig = CDbl(Evaluate("=MOD(" & Num1 & "," & Num2 & ")"))  думала, что это и есть остаток от деления на Num2  *крутит пальцем у виска*.  
Задача как раз-таки в том состоит, чтобы рассмотреть несколько генераторов псл. в том числе конгруэнтный, mother of all, метод фибоначчи с запаздываниями и т.д.    
Эммм..выходит, используя все эти методы, для получения равномерно распределенных чисел на [0, 1] нужно всегда на m делить? M=2^16, M=2^32. Так?
 
А вообще, как из полученных псевдослучайных чисел получить распределенные равномерно на отрезке [0,1] ?
Генераторы псч выдают как раз-таки псевдослуч. числа, но как получить из конкретного отрезка?
 
{quote}{login=}{date=15.03.2010 08:36}{thema=}{post}А вообще, как из полученных псевдослучайных чисел получить распределенные равномерно на отрезке [0,1] ?
Генераторы псч выдают как раз-таки псевдослуч. числа, но как получить из конкретного отрезка?{/post}{/quote}Очевидно, что для получения результата в интервале [0,1] нужно делить результат на максимально возможное (математически) значение. Там, где используется остаток от деления целого числа N на целое число M, нужно результат делить на M-1, потому что M-1 это максимально возможное значение остатка. Поэтому, вместо RndCongruent = Y / M мне нужно было написать RndCongruent = Y / (M - 1)
 
Может кто-нибудь силен в Delphi? Помогите, пожалуйста, перевести алгоритм для работы в ВБА:  
 
program MotherOfAll;  
 
var  
y : array [0..4] of real;
 
procedure InitRandom(seed : LongWord);  
var  
i : integer;  
s : int64;  
begin  
s := seed;  
for i := 0 to 4 do begin  
s := LongWord(s*1664525 + 1013904223);  
y[i] := s/4294967296;
end;  
end;  
 
function MotherOfAllRandom() : real;  
var  
b, c : extended;  
begin  
b := 2111111111.0;  
c := b*y[3] + 1492*y[2] + 1776*y[1] + 5115*y[0] + y[4];
y[4] := trunc©; y[3] := y[2]; y[2] := y[1]; y[1] := y[0]; y[0] := c - y[4];
y[4] := y[4]/4294967296;
result := y[0];
end;  
 
begin  
InitRandom(GetTickCount);//часы простой, но плохой способ инициации  
{...}  
end.  
 
Из теории  
Вычислительная формула:  
S= 2111111111*y[n-4] + 1492*y[n-3] + 1776*y[n-2] + 5115*y[n-1] + C,
x[n]=S/(2^32),
C=[S/(2^32)]
Здесь период имеет порядок 2^250. x[i] принадлежат [0, 1). Начальные их значения могут быть выбраны случайно
 
{quote}{login=kitikat}{date=15.03.2010 11:33}{thema=}{post}Может кто-нибудь силен в Delphi?{/post}{/quote}Может Вам здесь http://www.programmersforum.ru/forumdisplay.php?f=2  
спросить?
 
{quote}{login=kitikat}{date=15.03.2010 11:33}{thema=}{post}Может кто-нибудь силен в Delphi? Помогите, пожалуйста, перевести алгоритм для работы в ВБА:  
program MotherOfAll;...{/post}{/quote}  
Вот Вам VBA-аналог Delphi-кода:  
 
' http://bigmihan.narod.ru/pseudorandom.html  
' http://bigmihan.narod.ru/programs/mother.pas  
 
Dim y(0 To 4) As Double  
 
Sub InitRandom(seed As Double)  
 Dim i As Integer, s As Double  
 s = seed  
 For i = 0 To 4 ' Step -1  
   s = s * 1664525 + 1013904223  
   y(i) = s / 4294967296#  
 Next  
 ' ZVI: добавлено, чтобы прокрутить начальные нули  
 For i = 1 To 3  
   MotherOfAllRandom  
 Next  
End Sub  
 
Function MotherOfAllRandom() As Double  
 Dim b As Double, c As Double  
 b = 2111111111#  
 c = b * y(3) + 1492 * y(2) + 1776 * y(1) + 5115 * y(0) + y(4)  
 y(4) = Fix©: y(3) = y(2): y(2) = y(1): y(1) = y(0): y(0) = c - y(4)  
 y(4) = y(4) / 4294967296#  
 MotherOfAllRandom = y(0)  
End Function  
 
Sub test()  
 InitRandom Timer  
 For i = 1 To 100  
   Debug.Print MotherOfAllRandom  
 Next  
End Sub  
 
Не могли бы Вы пояснить, для чего Вам все это, и чем не устраивает встроенная в Excel функция СЛЧИСЛ()?  
Ведь если Вы запишите формулу =СЛЧИСЛ()  в Excel 2007 в весь столбец A, то не обнаружите ни одного повтора среди более миллиона (1048576) строк.  
А большой период 2^250 повторения псевдослучайных чисел еще не означает высокое качество генерации случайных чисел. Кроме того, и в Excel, и в VBA, и в Delphi и в т.п. программах числа представлены 15-ю значащими цифрами. Это означает, что в интервале [0,1] можно получить ряд максимум из 10^15 неповторяющихся чисел. А это примерно 2^50, и зачем Вам тогда алгоритм для ряда из 2^250 неповторяющихся чисел? :-)
 
Serge 007, спасибо за совет, ссылку, но мне нужно именно на ВБА, а не на Делфи.  
 
ZVI, где можно такой мозг как у Вас приобрести?)) Как всегда, на высоте)  
В общем, дело в том, что тема дипломной работы связана с оценкой коэффициентов линейной регрессии в случаях, когда в измеряемых данных имеются погрешности, существование которых неявно. Моделируем псевдослучайные величины с разными законами распределения - данные, по которым оцениваем в дальнейшем коэффициенты уравнения. Желательно подбирать такие данные, которые будут иметь бОльшую "случайность", будут независимы, также существует несколько тестов, по которым оценивается выборка на право называться "хорошей". Я, право, сама не знаю, зачем такие изыски, выборки в общем небольшие 500-1000 значений, да и показатели у rnd неплохие. Но научный руководитель настаивает :(  
 
И еще последний мучительный вопрос, посмотрите, пожалуйста, может для чьего-то мозга это понятно (ZVI, взято по Вашей ссылке).  
алгоритм для стьюпидов. можно ли как-то на ВБА раномерно распределенные на [0,1] знчения получить?
 
program KISS;{Keep It Simple Stupid}  
 
var  
x : LongWord = 123456789;  
y : LongWord = 362436000;  
z : LongWord = 521288629;  
c : LongWord = 7654321;  
 
function KissRandom() : LongWord;  
var  
t : int64;  
begin  
x := int64(69069)*x + 12345;  
y := y xor (y shl 13);  
y := y xor (y shr 17);  
y := y xor (y shl 5);  
t := int64(698769069)*z + c;  
c := t shr 32;  
z := t;  
result := x + y + z;  
end;  
 
begin  
{...}  
end.
 
{quote}{login=kitikat}{date=16.02.2010 10:03}{thema=линейный конгруэнтный метод - выработка псевдосл. чисел}{post}Уважаемые форумчане, здравствуйте! Помогите, пожалуйста, разобраться, почему при реализации линейного конгруэнтного метода выдается ошибка Run-time error '6' overflow - empty - пустое выражение (0). Прим. смотреть макрос{/post}{/quote}  
 
 
можешь выложить работу в рабочем состоянии, и если можно поясни что этот метод должен делать, точнее как он работает, не могу понять как он работает
Страницы: 1
Читают тему
Наверх