본문 바로가기

Autohotkey강좌

Autohotkey#46, RandBetween, 특정 범위에서 실수 난수(Random number) 발생하기

반응형

https://youtu.be/odJGwIr_5v0

기존에 임의의 숫자 발생기는 단순히 임의의 숫자(난수, random number)를 발생시켰는데, 일반적으로는 특정 범위내의 난수를 발생시키는게 일반적이므로 이번에는 해당 기능에 대해서 구현하는 것을 설명드립니다.

다시 한번 random number를 발생시키는 문법은 아래와 같습니다.

Random, no, StartNo, EndNo 

StartNo에서 EndNo사이에서 난수를 발생시켜 no에 저장합니다.

만약 원하는 갯수만큼 난수를 발생시키려면 loop를 그만큼 돌리면 됩니다.

Loop %Count%
{
  Random, no, StartNo, EndNo 
}

그렇다면, 해당 갯수만큼 발생시킨 결과를 하나의 변수에 저장하려면 어떻게 해야 할까요?

저장용 변수하나를 잡고, 기존 내용에 새로 생성한 결과를 더해주면 됩니다. 결과는 숫자이지만, 스트링으로 변환해서 스트링을 붙여주는 방식을 선택합니다.

  res := res  . no 

만약 구분자를 붙이려면 추가로 더 붙이면 됩니다. 아래에서는 줄바꾸기를 구분자로 붙였습니다.

  res := res  . no . "`n"

Loop마지막에 방금과 같은 내용을 넣으면 됩니다.

이제 기본적인 문법은 완성이 되었습니다. 그를 위한 gui를 구성해 봅니다.

우선 몇개만큼 생성할건지? 범위는 어디서부터 어디까지 생성할지를 만들어 주면 됩니다.

생성된 결과를 보여줄 변수를 Result에 저장해서 보여주기로 하고, 여러줄이 될 수 있으므로 크게 잡았습니다. 아래는 GUI구성안입니다.

Gui, Add, Text, x210 y5 w200 h20, Random Number Generator 
Gui, Add, Text, x60  y25  w150 h20 , How many (default:10) 
Gui, Add, Edit, x220 y25  w40 h20 vCount  ,10 ; count

Gui, Add, Text, x60  y55  w70 h20 , 범위 시작
Gui, Add, Edit, x140 y55  w50 h20 vStartNo  , 0 

Gui, Add, Text, x200  y55  w50 h20 , 범위 끝
Gui, Add, Edit, x260 y55  w50 h20 vEndNo  , 100

Gui, Add, Text, x60  y90  w50 h20 , Result
Gui, Add, Edit, r10 x120 y90  w400 h100 vResult, None

Gui, Add, Button, x270 y25 w70 h20, Generate ;
Gui, Add, Button, x350 y25 w70 h20, Exit ;
Gui, Submit, NoHide
Gui, Show, , Random No. Ver 1.1

 

여기까지 하면 기본적인 동작은 완성되는데, 추가적으로 소수단위로 시작과 끝을 입력하면 어떻게 될까요?

시작에는 0.2를 넣고, 끝을 100.53으로 넣고 난수를 발생시켰더니, 소수점 6자리까지 보여집니다. 이걸 원한게 아닌데....

우선 시작범위와 끝범위의 소수점이 다를 경우 더 넓은 범위로 보여주는 것으로 하고, 그렇게 하기 위해서는 소수점 이하 자리가 몇자리인지 알아내야 합니다. 어떻게 하면 가능할까요?

전체길이에서 소수점이 찍힌 자리만큼의 길이를 빼면 소수점이하 자리수를 알아낼 수 있지 않을까요?

스트링의 전체 길이를 알아내는 것은 StrLen()을 사용하면 가능합니다. 만약 특정 항목의 위치를 찾는 함수는 바로 InStr( hay, Stack )입니다. 따라서 StartNo에서 .의 위치를 찾아서 0보다 크면 소수점이 있는  float형이 입력된 것이므로 전체 길이에서 소수점위치를 빼면 나머지 소수점이하 자리수가 됩니다.

PosOfDot1 := InStr(StartNo,".")
if( PosOfDot1 >0 )
{
no1 := StrLen(StartNo)-PosOfDot1
} else
{
no1 :=0
}

EndNo에 대해서도 동일하게 적용해 줍니다. 이제 두가지 숫자중 더 큰 자리만큼 보여주면 원하는 결과가 됩니다.

no1이 2이고 no2가 3이라면 소수점이하를 3자리로 보여줘야 합니다. 소수점 자리를 제한하는 문법은 바로 SetFormat입니다. SetFormat,float, 0.3 이라면 소수점이하 3자리까지로 제한합니다.

no1과 no2중에서 큰수를 찾는 것은 max()함수를 사용합니다.

PosOfDot :=max(no1,no2)

소수점이하를 PosOfDot만큼으로 제한하려면 해당 PosOfDot의 내용으로 제한해야 합니다.

Pos = 0.%PosOfDot% 로하면 0.3이 표시가능합니다. 이제 SetFormat에 적용합니다.

SetFormat,float,%Pos%

loop를 돌면서 res에 순차적으로 저장해 왔으니 마지막에 Edit창 변수인 Result에 반영해 주면 됩니다.

GuiControl,, Result, %res%

 

여기까지만 구현하면 기본적인 기능은 구현이 됩니다.

현재 버전에 평균과 표준편차를 추가하려면 어떻게 해야 할까요?

우선 평균/표준편차를 감안해서 반영할지 말지를 결정하기 위해서 Radio버튼을 추가하고 그에 따라 행동을 다르게 할면 되겠습니다. 해당 메뉴를 추가하는 GUI는 다음과 같이 구성할 수 있습니다.

그러면 해당 라디오 버튼에 따라 평균/표준편차 사용여부를 저장하해줄 변수가 필요하고 그에 맞게 로직을 수정하면 됩니다. 평균/표준편차를 사용하지 않으면 기존대로 처리하면 되고, 만약 사용할 경우에는 별도의 처리가 필요합니다. 

우선 설정된 평균/표준편차는 목표치입니다. 하지만 실제로 생성된 데이터는 단순히 시작범위와 끝범위에서 생성된 내용이므로 보정이 필요합니다. 보정은 어떻게 가능할까요? 똑똑한 분들이 다 연구를 해 놓았습니다.

data' = mean + (data-mean')*stdev/stdev'

즉, 여기서 data, mean', stdev'는 시작범위와 끝범위내에서 생성된 데이터, 평균, 표준편차이고, mean, stdev는 해당 데이터들의 목표 평균과 표준편차입니다.  

이 경우 수정된 data'는 지정된 평균과 표준편차에 따라 시작이나 끝범위를 벗어날 수 있습니다. 따라서 가급적 평균과 표준편차는 중간에 위치하는게 좋습니다. 결국 생성된 배열에 대해서, 목표 평균과 표준 편차안에 존재하도록 보정해 주는 작업을 해서 수정된 값으로 저장해 줍니다. 그 결과 원하는 평균과 표준편차 범위내에서 데이터를 생성할 수 있습니다.

범위 시작을 0.00으로 넣고, 범위 끝을 100.0으로 넣고, 평균/표준편차 필요를 선택하고 평균과 표준편차를 50, 20으로 넣고 진행한 결과입니다.

최종적인 RandBetweenV1.2버전에 대한 스크립트입니다.

RandBetweenV1.2.ahk
0.00MB
RandBetweenV1.2.exe
0.61MB

반응형