Java

Java Random 함수의 동작 원리

체리필터 2021. 5. 14. 10:05
반응형

회사 내 스터디에서 다음의 책을 가지고 하고 있는데 쉬운 내용이지만 중간 중간 알게 되는 흥미로운 내용이 있어서 기록한다.

http://www.kyobobook.co.kr/product/detailViewKor.laf?ejkGb=KOR&barcode=9791163030072 

 

Do it! 자료구조와 함께 배우는 알고리즘 입문: 자바 편 - 교보문고

엄선된 88개의 실습 예제와 93개의 연습 문제! | IT 기업 시험, 면접 필수 역량인자료구조와 알고리즘의 기초를 100% 담아낸 책!IT 기업 코딩 면접, 필기 시험에서 당황하지 않으려면?눈으로 읽고 손

www.kyobobook.co.kr

 

일단 알게 된 내용은 2장에 나오는 Random 함수이며 Random 함수는 진짜 랜덤이 아니라는 것이다.

코드 내에서 사용하는 랜덤은 의사 난수라고 한다. 의사란 본뜰 의, 비슷할 사를 사용해서 진짜가 아니라 흉내낸 랜덤 값이라는 의미이다.

랜덤 함수는 무에서 랜더값을 생성하는게 아니라 seed(씨앗)이 주어지면 그 값을 기초로 만들게 된다.

따라서 seed가 같고 같은 컴퓨터라면 생성되는 난수는 같게 된다.

Java에서 Random 함수를 사용하는 방법은 아래와 같다.

Random random = new Random();
// or
Random random = new Random(1);

log.debug("random : {}", random.nextInt());

 

생성자에 넣는 파라미터 값은 seed 값이며 없을 경우에는 다음과 같이 생성한다.

    public Random() {
        this(seedUniquifier() ^ System.nanoTime());
    }

    public Random(long seed) {
        if (getClass() == Random.class)
            this.seed = new AtomicLong(initialScramble(seed));
        else {
            // subclass might have overriden setSeed
            this.seed = new AtomicLong();
            setSeed(seed);
        }
    }

 

어째든 seed와 컴퓨터 환경이 같으면 컴퓨터를 처음 키는 순간 난수표를 미리 만들어 둔 난수표에서 값을 가져다가 보여주게 된다.

과연 그런지 다음과 같은 테스트 코드를 돌려보자.

package com.example.demo.doit;

import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Random;

public class Algorithm02 {
    Logger log = (Logger) LoggerFactory.getLogger(Algorithm02.class);

    @Test
    public void RandomTest() {
        Random random = new Random(1);

        for (int i=0; i<10; i++) {
            log.debug("random : {}, {}", i, random.nextInt());
        }
    }
}

 

seed를 1로 고정한 상태에서 테스트 코드를 여러번 돌려 보면 다음과 같은 결과가 나온다.

// 1회차 테스트
09:45:27.647 [main] DEBUG com.example.demo.doit.Algorithm02 - random : 0, -1155869325
09:45:27.651 [main] DEBUG com.example.demo.doit.Algorithm02 - random : 1, 431529176
09:45:27.651 [main] DEBUG com.example.demo.doit.Algorithm02 - random : 2, 1761283695
09:45:27.651 [main] DEBUG com.example.demo.doit.Algorithm02 - random : 3, 1749940626
09:45:27.651 [main] DEBUG com.example.demo.doit.Algorithm02 - random : 4, 892128508
09:45:27.651 [main] DEBUG com.example.demo.doit.Algorithm02 - random : 5, 155629808
09:45:27.652 [main] DEBUG com.example.demo.doit.Algorithm02 - random : 6, 1429008869
09:45:27.652 [main] DEBUG com.example.demo.doit.Algorithm02 - random : 7, -1465154083
09:45:27.652 [main] DEBUG com.example.demo.doit.Algorithm02 - random : 8, -138487339
09:45:27.652 [main] DEBUG com.example.demo.doit.Algorithm02 - random : 9, -1242363800

// 2회차 테스트
09:45:47.163 [main] DEBUG com.example.demo.doit.Algorithm02 - random : 0, -1155869325
09:45:47.168 [main] DEBUG com.example.demo.doit.Algorithm02 - random : 1, 431529176
09:45:47.168 [main] DEBUG com.example.demo.doit.Algorithm02 - random : 2, 1761283695
09:45:47.168 [main] DEBUG com.example.demo.doit.Algorithm02 - random : 3, 1749940626
09:45:47.168 [main] DEBUG com.example.demo.doit.Algorithm02 - random : 4, 892128508
09:45:47.168 [main] DEBUG com.example.demo.doit.Algorithm02 - random : 5, 155629808
09:45:47.168 [main] DEBUG com.example.demo.doit.Algorithm02 - random : 6, 1429008869
09:45:47.168 [main] DEBUG com.example.demo.doit.Algorithm02 - random : 7, -1465154083
09:45:47.168 [main] DEBUG com.example.demo.doit.Algorithm02 - random : 8, -138487339
09:45:47.168 [main] DEBUG com.example.demo.doit.Algorithm02 - random : 9, -1242363800

// 3회차 테스트 (시간을 좀 더 두고 돌려 봄)
10:00:24.852 [main] DEBUG com.example.demo.doit.Algorithm02 - random : 0, -1155869325
10:00:24.858 [main] DEBUG com.example.demo.doit.Algorithm02 - random : 1, 431529176
10:00:24.858 [main] DEBUG com.example.demo.doit.Algorithm02 - random : 2, 1761283695
10:00:24.858 [main] DEBUG com.example.demo.doit.Algorithm02 - random : 3, 1749940626
10:00:24.858 [main] DEBUG com.example.demo.doit.Algorithm02 - random : 4, 892128508
10:00:24.858 [main] DEBUG com.example.demo.doit.Algorithm02 - random : 5, 155629808
10:00:24.858 [main] DEBUG com.example.demo.doit.Algorithm02 - random : 6, 1429008869
10:00:24.858 [main] DEBUG com.example.demo.doit.Algorithm02 - random : 7, -1465154083
10:00:24.858 [main] DEBUG com.example.demo.doit.Algorithm02 - random : 8, -138487339
10:00:24.858 [main] DEBUG com.example.demo.doit.Algorithm02 - random : 9, -1242363800

위에서 볼 수 있는 것 처럼 seed에 따라 이미 만들어진 내용을 리턴 하는 것으로 보여진다.

따라서 seed를 고정하게 되면 반복하게 되면서 제대로 된 난수가 나오지 않게 되고, 이를 방지하기 위해 계속 바뀌는 seed를 사용해야 한다.

Random 생성자 파라미터가 없을 경우 this(seedUniquifier() ^ System.nanoTime()); 와 같이 호출하는 것을 보면 seed를 랜덤하게 입력하기 위해 시간을 이용하는 것을 볼 수 있다.

 

반응형