Что нового

[Математика] Рандомный Random

bic

Знающий
Сообщения
46
Репутация
14
Есть несколько скриптов одновременно выполняющих Random (Пример 2). Результат получается нерандомный. Кажется это зависит от времени.
Надо чтобы в одновременно запущенных скриптах выполнялся рандомный рандом.

Пример 1. Получаем 20 случайных чисел.
Код:
#include <Array.au3>
Global $arRandom[20]

For $i = 0 To UBound($arRandom) - 1
	$random = Random(1, 1000, 1)
	$arRandom[$i] = $random
Next

_ArrayDisplay($arRandom)


Пример 2. Не получаем 20 рандомных чисел.
Компилим скрипт "script.exe"
Код:
$random = Random(1, 1000, 1)
ConsoleWrite($random)

Запускаем его с помощю скрипта:
Код:
#include <Array.au3>
Global $arRandom[20]

For $i = 0 To UBound($arRandom) - 1
	$PID = Run("script.exe", "", "", 0x2)
	While 1
		$Data = StdoutRead($PID)
		If $Data <> '' Then
			$arRandom[$i] = $Data
			ExitLoop
		EndIf
	WEnd
Next

_ArrayDisplay($arRandom)
 

Yashied

Модератор
Команда форума
Глобальный модератор
Сообщения
5,379
Репутация
2,724
Название из разряда "масло масляное".

:smile:

А если серьезно, то попробуй так:

Код:
SRandom(Number($CmdLine[1]))
$random = Random(1, 1000, 1)
ConsoleWrite($random)


Код:
#include <Array.au3>

Global $arRandom[20]

For $i = 0 To UBound($arRandom) - 1
	$PID = Run("script.exe " & Random(0, 65535, 1), "", "", 0x2)
	While 1
		$Data = StdoutRead($PID)
		If $Data <> '' Then
			$arRandom[$i] = $Data
			ExitLoop
		EndIf
	WEnd
Next

_ArrayDisplay($arRandom)
 
Автор
B

bic

Знающий
Сообщения
46
Репутация
14
Твой пример аналогичен примеру 1.
Скрипт, который создает массив, нужен лишь для того, чтобы показать проблему, он не должен ничего отправлять.
Два одинаковых скрипта в одно и то же время выдают одно и то же рандомное число.
Вопрос в том, что дописать в скомпилированный скрипт, чтобы рандом был разным в каждом из скриптов.
 

Yashied

Модератор
Команда форума
Глобальный модератор
Сообщения
5,379
Репутация
2,724
Если функция распределения для случайных чисел не важна, то можно так.

Код:
#include <Date.au3>

$tTime = _Date_Time_GetSystemTime()
$Seed = 1
For $i = 1 To 8
	$Seed *= DllStructGetData($tTime, $i)
Next
SRandom($Seed)
$random  = Random(1, 1000, 1)
ConsoleWrite($random)




Добавлено:
Сообщение автоматически объединено:

OffTopic:
Кстати, этот метод действительно немного портит функцию распределения случайных чисел, если реализован в одной программе, т.к. генератор случайных чисел существует в программе в единственном числе. По умолчанию функция распределения имеет линейный вид, это видно из первого результата (строки закомментированы). Если снять комментарии, то получается что-то не совсем линейное (не очень сильно), см. второй результат. В примере используется выборка из 100000 значений, думаю этого вполне достаточно.

Код:
#Include <Date.au3>

Dim $Data[10][2] = [[0.0, 0], [0.1, 0], [0.2, 0], [0.3, 0], [0.4, 0], [0.5, 0], [0.6, 0], [0.7, 0], [0.8, 0], [0.9, 0]]

For $i = 1 To 100000
;	$tTime = _Date_Time_GetSystemTime()
;	$Seed = 1
;	For $j = 1 To 8
;		$Seed *= DllStructGetData($tTime, $j)
;	Next
;	SRandom($Seed)
	$Val = Random(0, 1)
	For $j = 0 To UBound($Data) - 1
		If ($Val >= $Data[$j][0]) And ($Val <= $Data[$j][0] + 0.1) Then
			$Data[$j][1] +=1
			ExitLoop
		EndIf
	Next
Next
For $i = 1 To UBound($Data) - 1
	ConsoleWrite($Data[$i][1] & @CR)
Next

Результат 1

10180
10119
9949
10035
9980
10040
9919
9952
9967

Результат 2

9103
9408
8552
11304
12895
9276
10586
8443
8674
 

CreatoR

Must AutoIt!
Команда форума
Администратор
Сообщения
8,671
Репутация
2,481
Я эту багу заметил довольно давно, и воспроизводится она намного легче:

Код:
Run(@AutoItExe & ' /AutoIt3ExecuteLine "MsgBox(262144+64, ''Random Test 1'', ''Random: '' & Random(1, 5))"')
Run(@AutoItExe & ' /AutoIt3ExecuteLine "MsgBox(262144+64, ''Random Test 2'', ''Random: '' & Random(1, 5))"')

WinWait('Random Test 2')

WinMove('Random Test 1', 'Random: ', (@DesktopWidth/2)-200, (@DesktopHeight/2)-40)
WinMove('Random Test 2', 'Random: ', (@DesktopWidth/2)+100, (@DesktopHeight/2)-40)



Добавлено:
Сообщение автоматически объединено:

Yashied
Твой метод в большинстве случаев гинерирует разные числа, но иногда совпадает в точности:

Код:
$sTmpFile1 = _RunScript('Random Test 1')
$sTmpFile2 = _RunScript('Random Test 2')

WinWait('Random Test 2')

WinMove('Random Test 1', 'Random: ', (@DesktopWidth/2)-200, (@DesktopHeight/2)-40)
WinMove('Random Test 2', 'Random: ', (@DesktopWidth/2)+100, (@DesktopHeight/2)-40)

FileDelete($sTmpFile1)
FileDelete($sTmpFile2)

Func _RunScript($sTitle)
	Local $sScript = '#include <Date.au3>' & @CRLF
	$sScript &= '#NoTrayIcon' & @CRLF
	$sScript &= 'MsgBox(262144+64, ''' & $sTitle & ''', ''Random: '' & _RandomEx(1, 5))' & @CRLF
	$sScript &= 'Func _RandomEx($iMin, $iMax, $iFlag=0)' & @CRLF
	$sScript &= '	$tTime = _Date_Time_GetSystemTime()' & @CRLF
	$sScript &= '	$Seed = 1' & @CRLF
	$sScript &= '	For $i = 1 To 8' & @CRLF
	$sScript &= '		$Seed *= DllStructGetData($tTime, $i)' & @CRLF
	$sScript &= '	Next' & @CRLF
	$sScript &= '	SRandom($Seed)' & @CRLF
	$sScript &= '	Return Random($iMin, $iMax, $iFlag)' & @CRLF
	$sScript &= 'EndFunc' & @CRLF
	
	Local $sTmpFile = @TempDir & '\~au3_' & $sTitle & '.tmp'
	
	Local $hFile = FileOpen($sTmpFile, 2)
	FileWrite($hFile, $sScript)
	FileClose($hFile)
	
	Run(@AutoItExe & ' /AutoIt3ExecuteScript "' & $sTmpFile & '"')
;~ 	FileDelete($sTmpFile)
	Return $sTmpFile
EndFunc


Попробуй несколько раз позапускай скрипт.
 

Yashied

Модератор
Команда форума
Глобальный модератор
Сообщения
5,379
Репутация
2,724
Ну это не бага, это так и должно быть. Для случайной (от таймера) инициализации генератора случайных чисел, во многих языках программирования есть специальные функции, например Randomize() в Pascal и т.д. В AutoIt для этого есть SRandom(), но работает для произвольного значения. Я попытался зделать что-то на подобии Randomize(). Если две прграммы не запущены одновременно, вплоть до миллисекунды, то значения, возвращаемые функцией Random() не будут одинаковыми (в силу теории вероятности).
 
Автор
B

bic

Знающий
Сообщения
46
Репутация
14
Yashied
Ну в общем хороший результат, спасибо.
И да, иногда получается одинаковые числа, ну уж ладно.
 

Yashied

Модератор
Команда форума
Глобальный модератор
Сообщения
5,379
Репутация
2,724
CreatoR [?]
Твой метод в большинстве случаев гинерирует разные числа, но иногда совпадает в точности...

Ну... компьютеры нынче стали быстрыми... :smile: Вот так не будет совпадать.

Код:
$sTmpFile1  = _RunScript('Random Test 1')
Sleep(1)
$sTmpFile2 = _RunScript('Random Test 2')


А вообще, по хорошему, нужно написать свой ГСЧ отличный от AutoIt (для каждого экземпляра программы), и будет всем хорошо.



Добавлено:
Сообщение автоматически объединено:

OffTopic:
А вот интересно, как зделать ГСЧ с Гауссовским распределением?
 

Yashied

Модератор
Команда форума
Глобальный модератор
Сообщения
5,379
Репутация
2,724
CreatoR сказал(а):
Вы тут ребята ракету готовите, к запуску на марс?

:smile:

По теме.

CreatoR

Вот нашел очень простой способ для избавления от "повторений". Просто инициализируем ГСЧ от PID'а процесса.

Код:
SRandom(_WinAPI_GetCurrentProcessID())


Немного измененный твой пример.

Код:
$sTmpFile1 = _RunScript('Random Test 1')
$sTmpFile2 = _RunScript('Random Test 2')

WinWait('Random Test 2')

WinMove('Random Test 1', 'Random: ', (@DesktopWidth / 2) - 200, (@DesktopHeight / 2) - 40)
WinMove('Random Test 2', 'Random: ', (@DesktopWidth / 2) + 100, (@DesktopHeight / 2) - 40)

FileDelete($sTmpFile1)
FileDelete($sTmpFile2)

Func _RunScript($sTitle)
	Local $sScript = '#include <WinAPI.au3>' & @CRLF
	$sScript &= '#NoTrayIcon' & @CRLF
	$sScript &= 'MsgBox(262144+64, ''' & $sTitle & ''', ''Random: '' & _RandomEx(1, 5))' & @CRLF
	$sScript &= 'Func _RandomEx($iMin, $iMax, $iFlag=0)' & @CRLF
	$sScript &= '   SRandom(_WinAPI_GetCurrentProcessID())' & @CRLF
	$sScript &= '   Return Random($iMin, $iMax, $iFlag)' & @CRLF
	$sScript &= 'EndFunc' & @CRLF

	Local $sTmpFile = @TempDir & '\~au3_' & $sTitle & '.tmp'

	Local $hFile = FileOpen($sTmpFile, 2)
	FileWrite($hFile, $sScript)
	FileClose($hFile)

	Run(@AutoItExe & ' /AutoIt3ExecuteScript "' & $sTmpFile & '"')
;~  FileDelete($sTmpFile)
	Return $sTmpFile
EndFunc   ;==>_RunScript


И никаких повторений.

;)
 

CreatoR

Must AutoIt!
Команда форума
Администратор
Сообщения
8,671
Репутация
2,481
Yashied [?]
А не проще использовать @AutoItPID? :whistle:

Код:
Run(@AutoItExe & ' /AutoIt3ExecuteLine "MsgBox(262144+64, ''Random Test '' & SRandom(@AutoItPID), ''Random: '' & Random(1, 5))"')
Run(@AutoItExe & ' /AutoIt3ExecuteLine "MsgBox(262144+64, ''Random Test '' & SRandom(@AutoItPID)+1, ''Random: '' & Random(1, 5))"')

WinWait('Random Test 1')
WinWait('Random Test 2')

WinMove('Random Test 1', 'Random: ', (@DesktopWidth / 2) - 200, (@DesktopHeight / 2) - 40)
WinMove('Random Test 2', 'Random: ', (@DesktopWidth / 2) + 100, (@DesktopHeight / 2) - 40)


Афигенно, проблема решена, и действительно способ безумно простой :ok:
 

Yashied

Модератор
Команда форума
Глобальный модератор
Сообщения
5,379
Репутация
2,724
CreatoR [?]
А не проще использовать @AutoItPID?

Да, конечно, последнее время, что-то я забываю про родные функции (макросы) AutoIt. Надо бы еще перечитать справку.
 
Автор
B

bic

Знающий
Сообщения
46
Репутация
14
Yashied
CreatoR
Спасибо огромное, наконец то рандом стал рандомным.
Код:
SRandom(@AutoItPID)
$random  = Random(1, 1000, 1)
ConsoleWrite($random)
 

Yashied

Модератор
Команда форума
Глобальный модератор
Сообщения
5,379
Репутация
2,724
На здоровье, но только имей ввиду, что инициализировать ГСЧ в программе нужно только один раз и лучше в самом начале.
 

Garrett

Модератор
Локальный модератор
Сообщения
3,999
Репутация
967
Yashied
CreatoR
Может этот пример в "Полезняшки"
Отличный и полезный пример!
 

kaster

Мой Аватар, он лучший самый
Команда форума
Глобальный модератор
Сообщения
4,020
Репутация
626
Если, что весь оффтоп связанные с нормальным распределением перенес сюда http://autoit-script.ru/index.php?topic=1074.0
 
Верх