'반복문'에 해당되는 글 1건

  1. 2014.11.06 Random 클래스를 아십니까..? 1
dngchn's [C#]2014. 11. 6. 11:46

Random Number

亂數

亂(어지러울 란)자를 쓰니, 어지러운 수, 규칙없는 수가 되겠다.

굳이 우리말로 하자면.. 음.. 뭘까.. 꼴림수...?

암튼 난수가 필요하다.

아이스크림 쏘기 사다리를 타거나,

나 같은 경우는 디비에 더미데이터를 왕창 때려 넣기 위해서..


C#에서는 Random 클래스를 제공한다.

기본적인 사용법은 아래와 같다.

Random r = new Random();
randomNumber = r.Next(1, 11);

간단하다, Random 타입 객체를 생성하고, Next 메서드를 호출하여 난수를 얻는다.

Next 메서드의 인자로는 최소값, 최대값을 준다.

(*최대값은 원하는 최대값 + 1값을 넘긴다. 1부터 10까지 중 난수를 얻고자 한다면,

Next(1, 11); 과 같이...)


자, 한번 코드로 확인해보자.

우선 간단히 WPF로 프로젝트를 하나 만들자(WPF가 아닌 윈폼도 전혀 무방하다..).

화면엔 간단히 리스트 박스 하나로 꽉 채우자. 아래 처럼.

너무 썰렁한가..


코드도 썰렁하다.

    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
            DispatcherTimer timer = new DispatcherTimer();
            timer.Interval = TimeSpan.FromSeconds(2);
            timer.Tick += timer_Tick;
            timer.Start();
        }

        void timer_Tick(object sender, EventArgs e)
        {            
            string logString = string.Empty;

            for (int i = 0; i < 10; i++)
            {
                Random r = new Random();
                logString += (r.Next(1, 11).ToString() + " ");
            }
            
            this.resultLog.Items.Add(logString);
        }
    }

타이머를 하나 두어 반복적으로 실행시키고, 타이머 핸들러에서는 매 주기마다

1부터 10까지 수중 하나를 10개씩 만들어 리스트 박스에 표시하도록 했다.

어떤까.. 뭐 간단한 코드이니 더 들여다 볼것도 없다.

실행해보자.

...

이게 뭐냐.. 주기마다 난수가 생성되긴 하지만, 매 주기마다 반복문을 돌며 난수가 아닌 동일한 수가 만들어졌다.

분명, for문을 통해 반복적으로 Random 객체를 새로 생성해서 난수를 얻는데, 왜 10번 모두 같단 말인가..

(만일 주기마다 10개가 아닌 1개씩만 찍어보기로 했다면, 위 코드와 결과에서 어떤 이상함도 발견하지 못했을 수도 있다.)

...

이유는 간단하다. Random 객체는 시간을 seed로 삼아 생성된다. 위 코드에서는 반복문을 열라 빨리 돌면서,

거의 동시간(?)대, 즉 시간적으로 큰 차이를 보이지 않는 순간에 모두 생성되어, 동일한 구간의 난수를 만들어 내니,

10번의 결과가 모두 같은 것이었다.


그럼 이를 어떻게 해결하는가..

위 문제의 원인대로, Random 객체를 서로 비슷하지 않은 시간에 생성하면 될 것이다.

그러나, 위와 같은 시나리오에서는 Random 객체를 난수가 필요할 때마다 매번 생성시킬 필요는 없다.

처음 하나 만들어 두고 주구장창 써도 괜찮을 것이고, 오히려 이편이 매번 같은 시간대에 동일한 seed로 Random 객체를

생성시키지도 않을 것이다.


어디 한번 해보자.

    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
            DispatcherTimer timer = new DispatcherTimer();
            timer.Interval = TimeSpan.FromSeconds(2);
            timer.Tick += timer_Tick;
            timer.Start();
        }

        void timer_Tick(object sender, EventArgs e)
        {
            Random r = new Random();
            string logString = string.Empty;
            
            for (int i = 0; i < 10; i++)
                logString += (r.Next(1, 11).ToString() + " ");
            
            this.resultLog.Items.Add(logString);
        }
    }
}

Random 객체 생성 부분을 for문 밖으로 빼냈다.

(아예, 멤버로 선언하고, timer 핸들러 밖으로 빼내도 무방할 것이다. 타이머의 주기가 엄청 빨라지면 똑같이 동일한 문제가 발생할 수도 있으니...)


자, 이제 실행해보자.

뭐 이정도면 충분히 골고루다. 충분히 어지럽다... 끝.


Posted by dngchn