javaCopy code
import java.util.Random;
Random rand = new Random();
int randomNumber = rand.nextInt();
javaCopy code
double randomNumber = Math.random();
javaCopy code
import java.util.concurrent.ThreadLocalRandom;
int randomNumber = ThreadLocalRandom.current().nextInt();
예전에 어디서인가 들은 대화인대 기계가 절대하지 못하는 것 중 하나가 난수 생성이였다.
사람에게 1~10사이의 수를 말해줘 하면 매번 난수가 나올 수 있지만
프로그램의 난수는 “의사 난수”로서 결정론적인 알고리즘에 의해 생성된 수열이다
결국 예측 가능하다는 말이다.
이런 알고리즘 외에 외부 자연 현상을 기반을 생성되는 진짜 난수도 있기는 하다.
- 방사선 붕괴
- 방사선 물질이 방사선을 방출하면서 일정한 시간 간격으로 핵심이 붕괴된다.
이 때 붕괴 시간이 불확실해 이 측정값으로 진짜 난수를 생성할 수 있다.- 전기잡음
- 전기회로에서 발생하는 불규칙한 전압 변화로 불규칙성 + 무작위성을 가질 수 있다.
- 대기 진동
- 바람이나 대기의 마찰로 인해 발생하는 진동으로 무작위성을 가질수 있다.
Random 클래스는 시드 값을 기반으로
선형 합동 생성기 (Linear Congruential Generator, LCG) 알고리즘을 사용해서
의사 난수로 생성한다.
이 알고리즘은 의사난수를 생성할 수 있지만. 결국 패턴 , 규칙성이 파악 될 수 있다.
시드값이란?
난수 생성 알고리즘의 초기값을 의미한다 ( 시드머니 같이 )
시드 값을 지정하지 않으며 시스템 시간을 기반으로 시드값을 설정한다
시드값을 지정 : Random rand = new Random(1);
시간을 시드값으로 활용 : Random rand = new Random();
시드 값이 같을 경우 환경이 같은 경우 언제나 같은 값을 반환하기 때문에 주의해 사용해야 한다.
public static void main(String[] args) {
Random rand = new Random(1);
System.out.println(rand.nextInt()); // -1155869325
System.out.println(rand.nextInt()); // 431529176
System.out.println("==============================");
Random rand1 = new Random();
System.out.println(rand1.nextInt());
System.out.println(rand1.nextInt());
}
1번 실행 결과
-1155869325
431529176
==============================
-1095874602
1776211941
2번 실행 결과
-1155869325
431529176
==============================
-616803561
-1057413960
SecureRandom
를 객체로 전달해 난수를 생성하는 등의 방식이 있지만Java 7에서 추가된 난수 생성 클래스이다
Random과 Math.random과 동일하게 의사 난수를 발생하지만
내부의 static ThreadLocal
인스턴스를 활용해 각 스레드마다 독립적인 난수를 생성할 수 있다.
서로의 영향을 주지 않고 독립적으로 생성할 수 있다.
Random 클래스와 동일한 메소드들을 활용 할 수 있다.
import java.util.concurrent.ThreadLocalRandom;
int randomNum = ThreadLocalRandom.current().nextInt(0, 100);
current()
메소드를 통해 독립적인 스레드 객체를 반환한다.등이 난수가 필요로 하면서 쓰레드 세이프가 필요한 기능들이다.
물론 일반적인 환경에서는 의사 난수로 충분하다.
다만 보안이 필요할 경우 SecureRandom
클래스를 제공해 암호학적으로 안전한
난수를 만들어낼 수 있다. Random 클래스와 동일한 메소드를 제공하기 때문에.
Java에서 제공한 진짜 난수 생성기로 보안 관련 애플리케이션에서 사용된다.
java.security.SecureRandom
패키지에서 제공하는 클래스로
import java.security.SecureRandom;
SecureRandom sr = new SecureRandom();
byte[] bytes = new byte[16];
sr.nextBytes(bytes);
System.out.println(Arrays.toString(bytes));
결과
[89, -96, -39, -98, 81, 111, -66, -99, -65, -106, 24, 5, 5, -101, 59, -22]
이 코드는 16바이트 크기의 난수를 생성하는 코드이다.
내부적으로 랜덤한 데이터 소스를 사용해 안전한 난수를 생성한다 .
랜덤 데이터 소스의 예시는 운영체제에서 제공하는 하드웨어의 물리적인 속성
과
리눅스, 유닉스 기반 운영 체제에서 제공하는 /dev/random과 /dev/urandom 디바이스
가 있다.
하드웨어의 물리적 속성은 CPU, 메모리 , 마우스 움직임 , 키보드 타이밍같은 방식등이 있다.
위에서 말했을때에 진짜 난수의 예시는 대기진동, 전자기파등이 있었는데
SecureRandom 의 진짜 난수와는 차이점이 있지만. 완전히 예측할 수 없는 절대적인 난수를 불가능하다
예전에 본 어느 문장에서 생각이 비롯되 글을 쓰게 되었다.
결국 완전한 난수는 프로그램만으로는 불가능하지만
사람의 인지 수준에서는 난수라 판단 하기로 했다!