Страницы: 1 2 След.
RSS
Randomize + Rnd генерирует одинаковые числовые последовательности
 
Здравствуйте. Разрешите обратиться? Спасибо, обращаюсь :)

Реальная задача: покер, раздача карт на 2 или более игроков, количество вариантов (строк) любое (задается).
На основе задачи состряпал пример - 10 случайных уникальных чисел в строке. Два доп. столбца (A:B) - для помощи в подсчете повторов. Повторы (все дублированные) считаются в L2. Третий доп. столбец (справа, M) показывает позицию дубля строки. Галка - условие запуска ГСЧ (вкл/выкл)
Для уменьшения размера файла формулы в доп. столбцах удалены. Растянуть на нужное количество строк.

Обнаружил непонятное поведение Randomize: генератор случайных величин помогает создавать одинаковые числовые последовательности! и хочу понять причину этой ошибки

Варианты 1-2.
UDF не используем. Случайные значения получаем в основном макросе, Randomize  есть/нет.
Результат - повторов не обнаружено.

Вариант 3.
UDF используем. Без Randomize
Результат - повторов не обнаружено.
-------------- дальше интереснее --------------------------------------------------------------------------------
Вариант 4.
UDF используем. Randomize включаем напрямую, без условия Randomize вкл/выкл.
Результат - повторы строк зашкаливают. На 1000 вариантов строк с дублями - более 800

Вариант 5.
UDF используем. Randomize включаем через условие "Randomize вкл/выкл."
Результат - повторы есть, но на порядок меньше - не более 80

Еще наблюдение (проверять на варианте 4, там нагляднее).
Количество дублей одной строки зависит от количества строк. Это понятно - больше вариантов, больше вероятность повтора. Интересно другое: дубли повторяются через определенный промежуток. Количество строк в промежутке зависит от количества выводимых значений в одной строке! 10 значений - дубль через 26 строк, 6 значений - через 47-49 строк, при 4 значениях - через 81-82 строки...

Вопросы. Как объяснить такое нехорошее поведение генератора (вар. 4 и 5)?
1. Почему при включении генератора отдельной UDF последовательности дублируются?
2. Почему при включении Randomize через If дублей гораздо меньше?
3. Почему дубли повторяются через определенный промежуток?
код

Win7, Office-10, 32-bit
 
Вить, привет.
А где искать повторы? Внутри одной строки или вообще в целом одинаковые последовательности? Или в каждой строке должны быть числа, которых нет ни в одной другой строке? Не очень понял, потому что у меня повторов вообще нет в столбце В.

Win7, office 365 64-bit
Изменено: Дмитрий(The_Prist) Щербаков - 19.08.2018 13:37:52
Даже самый простой вопрос можно превратить в огромную проблему. Достаточно не уметь формулировать вопросы...
 
Внутри строки повторов нет, все замечательно. Повторение последовательностей (строк).
Сейчас в коде включен вариант 4, самый "повторяемый". Но в исходнике повторов нет, так как строк мало.
Растянуть формулы в столбцах A:B и M строк на 1000-2000. Запустить кнопкой. Если  L2>0 (а повторы будут), в столбце М число показывает, через сколько строк повторяется последовательность строки C:L
 
Генератор случайных чисел рассчитан на однократную инициализацию и дальнейший многократный вызов Rnd. В #1 Randomize вызывается много раз, причем без параметра.
Владимир
 
Это все понятно. И ясно, что перезапускать Randomize смысла нет. Вопрос в причине.
Генератор без параметра берет за основу отсчета текущие дату-время. Если вызывается многократно, то и основа меняется.
Повторы как получаются?
Если причина в запуске генератора для генерации каждой строки - почему повторы не все подряд, а через какой-то промежуток?
Логики  пока не вижу...
 
Поставьте счетчик на число вызовов f_rnd (там есть Randomize). У меня при 10000 строк получилось 98478 вызовов.
Владимир
 
Счетчик не нужен. По коду видно, что для получения значения  UDF может вызываться несколько раз (пока не найдет свободное число).

Я дорабатывал работу другого разработчика. Там такая вот беда и обнаружилась.
Еще раз:  вопрос об устойчивой повторяемости строк. Почему 10 (не одно-два - 10!) ,а в реальной задаче - строка из 23 значений - повторяется "число в число"? И это при использовнии ГСЧ.
 
Если на 10000 строк Randomize выполнить олин раз (перенести из f_rnd в Rndrows), то у меня повторов нет.
Владимир
 
Владимир, внимательнее )
В первом сообщении я описал варианты.  Интересуют варианты 4 и 5. И в конце три вопроса касаемо только этих вариантов.
Не "так делать не надо", а по-че-му? А вдруг причина дублирования большого набора значений еще где-нибудь может себя проявить?

Пока вижу только одно: каким-то образом начало отсчета генератора повторяется. Но ведь Rnd все равно находит случайную величину? Т.е. даже при одинаковом начале двух генераций наборы чисел должны быть разными.
 
удаляем Randomize из Function fRnd_
вставляем Randomize первой строкой в Sub RndRows
повторов нет! (появятся при ОЧЕНЬ большим количестве строк)
я пользовался всегда так:
ОДНА инициализация генератора и получение безконечного (на практике любого необходимого) количества случайных чисел
Программисты - это люди, решающие проблемы, о существовании которых Вы не подозревали, методами, которых Вы не понимаете!
 
Игорь, сообщение №1 и сообщение №9!
Цитата
vikttur написал: Я дорабатывал работу другого разработчика... Не "так делать не надо", а по-че-му?
Причину понять хочу.
Под  краном не ходить! - почему? Потому что кирпич со лбом встретится. Понятно? Более чем.
Не запускать ГСЧ 250 миллионов раз! - почему? О каком кирпиче речь?
 
вариант 4 и 5:
Randomize удаляем из пользоветельской функции, запускаем 1 раз при Workbook_Open в результате пользоветельской функцией возможно получить приблизительно 10^15 случайных, не повторяющихся значений
Программисты - это люди, решающие проблемы, о существовании которых Вы не подозревали, методами, которых Вы не понимаете!
 
>>Муля, не нервируй меня :)
То, что вар. 4 и 5 можно преобразовать в 1-3, понятно и эти варианты описаны в стартовом сообщении. Вот если бы ты о кирпиче рассказал...
 
Боюсь, что никто не ответит
Виктор, нарвался на повторяющиеся последовательности "случайных" чисел при многократном использовании Randomize - возрадуйся! и положи эти знания в копилку (я уже сделал это, спасибо тебе за наблюдательность))
Программисты - это люди, решающие проблемы, о существовании которых Вы не подозревали, методами, которых Вы не понимаете!
 
Рано радоваться. Играться со зверем, не зная наперед его реакции - чревато. Поэтому и тему создал.
 
Я согласен с Игорем. Функция rnd генерирует "псевдослучайные" числа, так как каждый новый член последовательности однозначно определяется предыдущим. Естественно, ее нельзя использовать в серьезных приложениях (например, лотереях). В #1 ставится вопрос о закономерностях в последовательности результатов работы другой функции:
Код
Function fRnd_()
    Randomize
    fRnd_ = Int(Rnd * 52 + 1)
End Function

(52 можно заменить на любое целое, большее 1).

Затрудняюсь пока сделать какие-либо практические выводы.
Владимир
 
Из справки

Соломинка...
Во первых, откуда этому минусу взяться? Во-вторых, "повторить" - это воспроизвести то же, что было до этого. А тут - через какой-то промежуток.

Из справки

Начальное значение при каждом запуске разное. Уменьшение количество дублей по варианту 5 (при включении Randomize по условию) логически можно понять: If срабатывает с определенной задержкой и это отсеивает варианты запусков.
Повторение случайно одного-двух чисел еще допускаю, но как повторяются строки из 10 (23) значений - загадка.  Тем более, что эти 10 значения получаются после 10-52 включений Randomize для каждого из них.
Цитата
sokol92 написал: Функция rnd генерирует "псевдослучайные" числа, так как каждый новый член последовательности однозначно определяется предыдущим.
Да, и повторы возможны, если допустить, что основа Rnd одинакова. Вызвали Randomize с одинаковым стартом - получили одинаковую последовательность. Наверное, возможно. Но  получить одинаковое после [от мин=10 до макс=10*52]?

Похоже на написание "Войны и Мира" мартышками :)
Скрытый текст
 
Следующий пример иллюстрирует использование отрицательных чисел. Последовательности во всех столбцах должны быть одинаковы.
Код
Sub test()
  Dim i As Long, j As Long
  For j = 1 To 20
    Rnd -0.5
    For i = 1 To 100
      Cells(i, j) = Rnd
    Next i
  Next j
End Sub
Насколько я понимаю, задача Randomize - начать новую последовательность "псевдослучайных" чисел. Про равномерное распределение на отрезке [0;1] стартовых членов последовательности речи не идет. Сами же стартовые члены, похоже, не повторяются.
Изменено: sokol92 - 19.08.2018 18:07:08
Владимир
 
Спасибо,  свою ошибку в применении отрицательных понял. Считал, что это относилось к Randomize.

Цитата
sokol92 написал: Про равномерное распределение на отрезке [0;1] стартовых членов последовательности речи не идет.
Нет, я о другом писал. О случае, когда после одного запуска Randomize генерируется вся последовательность.
Псевдослучайные. Следующий элемент зависит от предыдущего. Если допустить, что при старте генератора задается одинаковое начальное, то есть вероятность, что появятся одинаковые последовательности.  Но в данной задаче начальные значения всегда разные (Now) и не один запуск - последовательность, а несколько запусков - значение

Почему уцепился?
Ошибка стандарта вычислений. Понятно, как избежать. Логически понятна и причина.
Здесь же понятно, как не допустить, но логики в дублировании не наблюдается. Беда мозгу, беда...
 
Следующий тест на моей конфигурации показывает, что при 100000 вызовов cтартовые значения Rnd после Randomize повторяются 1-2 раза (почти 85% два раза). Это много, даже учитывая, что Rnd генерирует тип Single (не более 7 значащих цифр). Кроме того, в #1 единичный отрезок разбивается на 52 равных части и анализируется последовательность попаданий в эти подотрезки, а не равенство значений последовательности.
Код
Sub test()
  Dim i As Long
  For i = 1 To 100000
    Randomize
    Cells(i, 1) = Rnd
  Next i
End Sub

Если бы Randomize анализировал только Now (время с точностью до секунды), то он бы повторял свои значения (учитывая скорость заполнения массивов в #1). Даже Timer недостаточен (на слабой конфигурации) для генерации разных последовательностей ввиду низкой точности Single (выполнять только вечером до 23:59 :) ) :

Код
Sub Test2  
  Dim i As Long
  For i = 1 To 50
    Debug.Print Timer
    DoEvents
  Next i
End Sub

Вывод: не используем rnd для серьезных целей.
Владимир
 
Ну почему не используем? (не о серьезности, а о повторах)
Если использовать из первого сообщения
Код
            Do While Not aCard(lNumRnd, 2) ' поиск свободного значения
                lNumRnd = Int(Rnd * 52 + 1) 
            Loop

то повторов можно избежать. Другое дело, что чем больше диапазон результирующий и чем ближе по величине диапазоны исходный и результирующий, тем больше итераций для поиска свободного значения.
 
Часто покерные комбинации дело серьезное и не случайное :)  
Владимир
 
За неслучайное можно серьезно и как бы случайно по шапке получить :)

Цитата
sokol92 написал:  в #1 единичный отрезок разбивается на 52 равных части и анализируется последовательность попаданий в эти подотрезки, а не равенство значений последовательности.
Да, но одинаковые последовательности как-то же формируются?
 
Цитата
vikttur написал #19:
после одного запуска Randomize генерируется вся последовательность.
Randomize НЕ генерирует последовательность, а только устанавливает её начальное значение,
каждое следующее значение Rnd - функция предыдущего значения.
Если в цикле ставить Randomize перед каждым вызовом Rnd, то Now просто не успевает измениться
и Randomize создаёт начальное значение с тем же значением Now.
Изменено: С.М. - 20.08.2018 00:43:11 (С американским языком плохо :-()
 
Цитата
после одного запуска Randomize генерируется вся последовательность.
Ну, не дописал, что с помощью Rnd _)

С.М., спасибо, нужная инормация. Это объясняло бы 10-20 одинаковых строк подряд. Как объяснить повтор через промежуток?
Цитата
vikttur написал: 10 значений - дубль через 26 строк, 6 значений - через 47-49 строк, при 4 значениях - через 81-82 строки...
 
Виктор, ну так через несколько итераций в цикле Now таки изменяется, но не намного. Может поэтому и возникает повторяемость (?).
Изменено: С.М. - 20.08.2018 00:44:06
 
Еще более непонятно... Если New изменяется, то почему последовательность повторяется?
Хотя как причина - может быть... Чем меньше значений в строке, тем больше промежуток... Очень похоже.

Цитата
Если в цикле ставить Randomize перед каждым вызовом Rnd, то New просто не успевает измениться
Сомнения.
Как объяснить работу немного измененного кода Владимира:
Код
Sub test11()
Dim i As Long, j As Long
    For j = 1 To 20
        Randomize
    
        For i = 1 To 100
            Cells(i, j) = Rnd
        Next i
    Next j
End Sub

Перезапускаем в цикле, но значения в строках не повторяются.
 
То, что Randomize генерирует разные стартовые значения при последовательных вызовах даже на коротком промежутке времени, видно по 1-му тесту из #20. Так что на 20 столбцах в #27 они не успевают повториться.
Уважаемый модератор. Приведите код в порядок с помощью кнопки <...>  (чуть-чуть опоздал  :D )
Изменено: sokol92 - 19.08.2018 20:35:14
Владимир
 
:)
Итак, что имеем.
Randomize для получения стартового значения использует текущие дату-время. Именно "использует", вычисляя старт по какому-то алгоритму.

В одну и ту же секунду (правильнее -  какое-то время T):
- стартовое значение разное;
- если в цикле запустить Rnd, будут сформированы разные последовательности;
- если в цикле вызывать Randomize+Rnd, получим разные отдельные значения.

Время T = T + х
- стартовые значения повторяют предыдущий комплект;
-  Rnd в цикле сформирует дубли предыдущего блока;
-  Randomize+Rnd в цикле повторит предыдущие последовательности.

Теорию подтверждают:
- уменьшение дублей при задержке определения истинности If;
- уменьшение дублей (увеличение расстояния между ними) при уменьшении количества значений в строке;
- добавление задержки убрало дубли:
Код
Application.Wait Time:=Now + TimeValue("0:00:01")
    Randomize

Если теория ошибочна, бросьте в меня (правильнее - в С.М. и sokol92, они виноваты) камнем правильной :)
 
Цитата
sokol92 написал #28:
Так что на 20 столбцах в #27 они не успевают повториться.
На Лист2 (Randomize - внутри цикла) - повторяются,
а на Лист4 (Randomize - перед циклом) - нет
---------------
На Лист1 - таблица 100x20 с повторами.
Изменено: С.М. - 19.08.2018 21:58:26 (Заменил файл)
Страницы: 1 2 След.
Наверх