안녕하세요, 여행벌입니다.

오늘은 자바 랜덤 난수 생성하는 2가지 방법에 대해서 포스팅해보겠습니다.


java.util.Random 클래스 이용

Random 클래스를 이용하면 여러 가지 자료형에 대해서 랜덤 난수를 생성할 수 있습니다.

( import를 해줘야 사용할 수 있습니다. )

random.nextBoolean(); // true 아니면 false를 생성
random.nextInt(); // Int 형 범위에서 정수를 랜덤하게 생성
random.nextInt(N); // 0 ~ N - 1 범위에서 정수를 랜덤하게 생성
random.nextLong(); // Long 형 범위에서 정수를 랜덤하게 생성
random.nextFloat(); // 0.0F ~ 1.0F 사이에서 실수를 랜덤하게 생성
random.nextDouble(); // 0.0D ~ 1.0D 사이에서 실수를 랜덤하게 생성

 가장 자주 쓰이는 메소드는 nextInt() 함수로 매개변수를 통해 범위를 지정할 수 있습니다.

 물론, 이 난수들은 유사 난수(Pseudo Random Number)입니다. 즉, 컴퓨터가 가지고 있는 랜덤 알고리즘에 의해서 생성되는 난수들이지 정말 랜덤하게 생성되는 수는 아닙니다. 

package Hello;
import java.util.Random;

public class randomTest {
	public static void main(String args[]) {
		Random random = new Random();
		System.out.println("nextBoolean : " + random.nextBoolean());
		System.out.println("nextInt : " + random.nextInt());
		System.out.println("nextInt : " + random.nextInt(100));
		System.out.println("nextLong: " + random.nextLong());
		System.out.println("nextFloat : " + random.nextFloat());
		System.out.println("nextDouble : " + random.nextDouble());
	}
}
// Console
nextBoolean : true
nextInt : 540532811
nextInt : 15
nextLong: -1389414493932819308
nextFloat : 0.20302159
nextDouble : 0.44444974642727286

java.lang.Math 클래스 이용

 Math 클래스는 java.lang 패키지에 있으므로 별도로 import 할 필요는 없습니다. 또, Math 클래스의 random() 메소드는 Static 메소드이므로 객체를 생성하지않고 사용할 수 있습니다.

 Math.random() 메소드는 0.0D ~ 1.0D 난수를 발생합니다.

package Hello;

public class randomTest {
	public static void main(String args[]) {
		System.out.println("Math 클래스 난수 : " + Math.random());
	}
}
Math 클래스 난수 : 0.9956712501922751

 그럼 Math.random() 함수를 이용해서 0 ~ 9 사이의 숫자를 랜덤하게 얻고 싶으면 어떻게 해야 할까요?

package Hello;

public class randomTest {
	public static void main(String args[]) {
		System.out.println("Math 클래스 난수(0~9사이 정수 난수발생) : " + (int)(10*Math.random()));
	}
}

 다음과 같이 10을 곱해주고 강제 형 변환을 통해 소수점 뒤의 숫자들을 날려주면 됩니다.


 

안녕하세요, 여행벌입니다.

오늘은 자바 비트 연산자에 대해서 다뤄보겠습니다.


비트 연산자


 비트 연산자는 각각의 비트를 대상으로 연산을 진행하는 연산자이며 피연산자는 반드시 정수이어야 합니다. 실수를 대상으로 하는 비트 연산은 의미가 없기에 자바에서 지원하지 않습니다.


비트 연산자 : &, |, ^, ~


연산자

연산자의 기능

결합 방향

&

비트 단위로 AND 연산을 한다.

|

비트 단위로 OR 연산을 한다.

^

비트 단위로 XOR 연산을 한다.

~

피연산자의 모든 비트를 반선시켜서 얻은 결과를 반환한다.


예제 1)


package Hello;

public class HelloWorld {
	public static void main(String args[]) {
		int a = 8; // 1000(2)
		int b = 4; //  100(2);
		System.out.printf("a & b : %d\n", a & b);
		System.out.printf("a | b : %d\n", a | b);
		System.out.printf("a ^ b : %d\n" , a ^ b);
		System.out.printf("~a : %d" , ~a);
	}
}

a는 8로 2진수로 표현하면 0000 0000 0000 0000 0000 0000 0000 1000(2)

b는 4로 2진수로 표현하면 0000 0000 0000 0000 0000 0000 0000 0100(2) 와 같습니다.

따라서, 비트 연산 & 를 진행하면 각 비트 별로 AND 연산이 진행되고,

0000 0000 0000 0000 0000 0000 0000 0000(2) 가 됩니다.

비트 연산 | 를 진행하면 각 비트 별로 OR 연산이 진행되고,

0000 0000 0000 0000 0000 0000 0000 1100(2) 가 됩니다.

비트 연산 ^ 를 진행하면 각 비트 별로 XOR 연산이 진행되므로

0000 0000 0000 0000 0000 0000 0000 1100(2) 가 됩니다.

비트 연산 ~ 를 진행하면 a의 각 비트를 0 이면 1, 1이면 0으로 바꾸므로

1111 1111 1111 1111 1111 1111 1111 0111(2) 가 됩니다.

따라서 결과는 0, 12, 12, -9가 됩니다.

a & b : 0
a | b : 12
a ^ b : 12
~a : -9

비트 쉬프트 연산자 : <<, >>, >>>


 비트 쉬프트 연산자는 피연산자의 비트 열을 왼쪽 또는 오른쪽으로 이동시킨 결과를 반환하는 연산자입니다. 두 개의 피연산자가 필요한 이항 연산자이며, 피연산자는 모두 정수여야 합니다.

연산자

연산자의 기능

결합 방향

<<

■ 피연산자의 비트 열을 왼쪽으로 이동

■ 이동에 따른 빈 공간은 0으로 채움

>>

■ 피연산자의 비트 열을 오른쪽으로 이동
■ 이동에 따른 빈 공간은 음수의 경우 1, 양수의 경우 0으로 채움

>>>

■ 피연산자의 비트 열을 오른쪽으로 이동
■ 이동에 따른 빈 공간은 0으로 채움


예시 2)


package Hello;

public class HelloWorld {
	public static void main(String args[]) {
		byte num = 2; // 00000010 (2)
		System.out.println((byte)(num << 1)); //00000100(2)
		System.out.println((byte)(num << 2)); //00001000(2)
		System.out.println((byte)(num << 3)); //00010000(2)
		
		num = 13; // 00001101 (2)
		System.out.println((byte)(num >> 1)); // 00000110(2)
		System.out.println((byte)(num >> 2)); // 00000011(2)
		System.out.println((byte)(num >> 3)); // 00000001(2)
		
		num = -8; // 11111000 (2)
		System.out.println((byte)(num >> 1)); // 11111100(2)
		System.out.println((byte)(num >> 2)); // 11111110(2)
		System.out.println((byte)(num >> 3)); // 11111111(2)
	}
}
4
8
16
6
3
1
-4
-2
-1

 

안녕하세요, 여행벌입니다.

오늘은 자바 연산자 중 단항 연산자들에 대해서 다뤄보겠습니다.


단항 연산자


 단항 연산자는 피연산자가 하나인 연산자로 이항 연산자에 비해 그 수가 적습니다.


부호 연산자 : +, -


 +, - 는 이항 연산자로 사용되면 덧셈과 뺄셈에 사용되지만, 단항 연산자로 수학에서와 동일한 의미를 갖습니다. 이때, 자바는 기본적으로 정수형 연산을 int 형으로 진행하고 그 결과도 int 형으로 반환하고, 실수형 연산을 double형으로 진행하고 그 결과도 double 형으로 반환하므로 부호 연산자를 사용할 때도 이 점을 주의해야 합니다.


예시 1)


package Hello;

public class HelloWorld {
	public static void main(String args[]) {
		int num = 5;
		System.out.println(-num);
	}
}
-5

 위의 코드는 부호 연산자 - 를 이용해 num 의 부호를 바꿔서 출력했습니다.

package Hello;

public class HelloWorld {
	public static void main(String args[]) {
		short num = 5;
		short num2 = -num;
	}
}

 위의 코드를 실행하면 num2 에는 -5가 저장될까요? 정답은 -num 은 int 형이지만 num2 는 short 형이므로 에러가 발생합니다.


증가 및 감소 연산자 : ++,  --


연산자

연산자의 기능

결합 방향

++ (Prefix)

피연산자에 저장된 값을 1 증가시킵니다.

val = ++n;

-- (Prefix)

피연산자에 저장된 값을 1 감소시킵니다.

val = --n;

++ (Postfix)

피연산자에 저장된 값을 1 증가시킵니다.

val = n++;

-- (Postfix)

피연산자에 저장된 값을 1 감소시킵니다.

val = n--;

 증가 및 감소 연산자 ++, -- 는 피연산자의 앞부분에 붙이냐, 뒷부분에 붙이냐에 따라 작동하는 방식이 조금 다릅니다. 기본적으로 값이 하나 증가 및 감소하는 것은 동일하나 반영되는 시점에 차이가 있습니다. Prefix 방식은 연산으로 인한 값의 증가 및 감소가 연산이 진행된 문장에서 발생하고, Postfix 방법은 그다음 문장으로 넘어가야 반영이 됩니다.


예시 2)


package Hello;

public class HelloWorld {
	public static void main(String args[]) {
		int num1 = 5, num2 = 5;
		System.out.println("num1++ : " + num1++ + ' ' + "++num2 : " + ++num2);
		System.out.println("num1-- : " + num1-- + ' ' + "--num2 : " + --num2);
	}
}
num1++ : 5 ++num2 : 6
num1-- : 6 --num2 : 5

 결국 모든 코드를 수행하고 나서 num1, num2 에 모두 5가 저장되지만 적용되는 시점에 따라 출력되는 값이 다른 것을 확인할 수 있습니다.


 

안녕하세요, 여행벌입니다.

오늘은 자바 연산자 중 이항 연산자들에 대해서 다뤄보겠습니다.


자바 연산자 종류


연산기호

결합 방향

우선순위 ( 낮을수록 높음 )

[ ], ( ), .

expr++, expr--

2

++expr, --expr, +expr, -expr, ~, !, (type), new

3

*, /, %

4

+, -

5

<<, >>, >>>

6

<, >, <=, >=, instanceof

7

==, !=

8

&

9

^

10

|

11

&&

12

||

13

? expr : expr

14

=, +=, -=, *=, /=, %=, ^=, |=, <<=, >>=, >>>=

15


이항 연산자


 피연산자가 둘인 연산자를 가리켜 '이항 연산자(binray operator)' 라 합니다. 피연산자는 데이터 그 자체를 대표함과 동시에 조작, 연산에 사용할 데이터를 지정하는 컴퓨터 명령의 일부입니다.


대입 연산자와 산술 연산자 : =, +, -, *, /, %


연산자 연산자의 기능 결합 방향
=

연산자 오른쪽에 있는 값을 연산자 왼쪽에 있는 변수에 대입.

a = 5;

+

두 연산자의 값을 더한다.

a = 4 + 3;

-

왼쪽의 피연산자 값에서 오른쪽의 피연산자 값을 뺀다.

a = 4 - 3;

*

두 피연산자의 값을 곱한다.

a = 4 * 3;

 

/

왼쪽의 피연산자 값을 오른쪽의 피연산자 값으로 나눈 몫을 반환한다.

a = 4 / 3;

%

왼쪽의 피연산자 값을 오른쪽의 피연산자 값으로 나눴을 때

얻게 되는 나머지를 반환한다.

a = 4 % 3;

 


복합 대입 연산자 : +=, -=, *=, /=, %=, &=, ^=, <<=, >>=, >>>=


연산자 연산자의 기능
+= a += b 는 a = a + b; 와 같습니다
-= a -= b 는 a = a - b; 와 같습니다.
*= a *= b 는 a = a * b; 와 같습니다.
/= a /= b 는 a = a / b; 와 같습니다.
%= a %= b 는 a = a % b; 와 같습니다.
&= a &= b 는 a = a & b; 와 같습니다.
^= a ^= b 는 a = a ^ b; 와 같습니다.
<<= a <<<= b 는 a = a << b; 와 같습니다.
>>= a >>= b 는 a = a >> b; 와 같습니다.
>>>= a >>>= b 는 a = a >>> b; 와 같습니다.

관계 연산자 : <, >, <=, >=, ==, !=


 관계 연산자는 두 개의 피연산자 사이에서 크기 및 동등 관계를 따져주는 이항 연산자로 결과에 따라서 true 또는 false를 반환합니다.

연산자 연산자의 기능 결합 방향
<

a < b

a 가 b 보다 작은가?

>

a > b

a 가 b 보다 큰가?

<=

a <= b

a 가 b 보다 작거나 같은가

>=

a >= b

a 가 b 보다 크거나 같은가

==

a == b

a 가 b 랑 같은가?

!=

a != b

a 가 b랑 다른가?


논리 연산자 : &&, ||, !


연산자 연산자의 기능 결합 방향
&&

A && B

A와 B 모두가 true이면 true, 아니면 false ( 논리 AND 와 동일 )

||

A || B

A와 B 모두가 false이면 false, 아니면 true ( 논리 OR 과 동일 )

!

!A

A가 true이면 false, false이면 true 반환 ( 논리 NOT )


예시 1)


package Hello;

public class HelloWorld {
	public static void main(String args[]) {
		int num1 = 0;
		int num2 = 0;
		boolean result;
		
		result = ((num1 += 10) < 0) && ((num2 += 10) > 0);
		System.out.println(result);
		System.out.println(num1);
		System.out.println(num2);
	}
}

 위의 출력 결과는 어떻게 될까요?

false
10
0

 num1은 10이지만, num2는 0인 것을 확인할 수 있습니다. 그 이유는 && 연산자 때문입니다. ( (num1 += 10) < 0 ) 이 먼저 수행되는데, num1 += 10을 하면 num1은 10이 되므로 0보다 작지 않습니다. 따라서 ( (num1 += 10) < 0 ) 은 false가 됩니다. 이때, && 연산자는 false가 하나라도 존재하면 어차피 false 값을 같습니다. 따라서 ( (num2 += 10) > 0) 연산을 진행하지 않고 result 에는 false가 저장됩니다. 


예시 2)


package Hello;

public class HelloWorld {
	public static void main(String args[]) {
		int a = 5; // 코드 1번
		System.out.println(a++); // 코드 2번
		System.out.println(a); // 코드 3번
		System.out.println((a++ + 5) * 3); // 코드 4번
		a = (a++ + 5) * 3; // 코드 5번
		System.out.println(a); // 코드 6번
	}
}

 위의 코드는 어떤 값들을 출력할까요? 정답은 아래와 같습니다!

5
6
33
36

 코드 1번에서 a 에 5를 할당합니다.

 코드 2번에서는 a를 출력한 후, ++ 연산이 진행되므로 '5'를 출력하지만 a의 값은 6이 됩니다.

 코드 3번은 코드 2번에 의해 '6' 을 출력하게 됩니다.

 코드 4번에는 ( ) , ++, +, * 4가지 연산이 등장합니다. 우선순위는 ( ), ++, *, + 순으로 괄호 안에 식을 먼저 진행해야 됩니다. 따라서 ++ 과 + 연산이 진행되는데 이때, ++ 연산은 명령을 마무리 한 후에 a의 값을 올려주므로 (6 + 5) 가 진행됩니다. 그 후 * 3을 해서 33이라는 값이 만들어지고 a는 1 증가해서 7이 됩니다. 

 코드 5번은 ( ), ++, +, * , = 5가지 연산이 등장합니다. 우선순위는 ( ), ++, *, +, = 순으로 코드 4번과 마찬가지로 괄호 안에 식을 먼저 진행해야됩니다. 따라서 (7 + 5) 가 먼저 계산되고, 12 * 3이 계산되고 ++ 연산에 의해 a는 1 증가해서 8이 됩니다. 하지만 = 연산에 의해 계산된 36이란 값이 a에 저장되므로 a는 결국 36이 저장됩니다.


예시 3)


package Hello;

public class HelloWorld {
	public static void main(String args[]) {
		int a = 1; // 코드1
		a = ~a; // 코드2
		System.out.println(a); // 코드3
	}
}

 위의 예시는 어떤 값을 출력할까요?

-2

 정답은 '-2' 입니다.

 컴퓨터는 모든 숫자를 2진수로 저장합니다. 우리는 앞의 포스팅에서 int 는 4바이트로 이루어져 있다고 배웠습니다. 따라서, a에 1을 할당하면 다음과 같이 컴퓨터에는 저장됩니다.

 a = 0000 0000 0000 0000 0000 0000 0000 0001 (2)

 ~ 연산은 쉽게 말하면 2진수로 저장된 a의 비트들을 반대로 바꿔주는 연산입니다. 즉, 코드2에 의해 a는 다음과 같이 바뀝니다.

 a = 1111 1111 1111 1111 1111 1111 1111 1110 (2)

 컴퓨터가 정수는 저장하는 방법인 2의 보수법에 의하면 위의 2진수 코드는 '-2' 를 의미합니다. 따라서 -2가 출력됩니다.


예시 4) 비트 연산자


 << 연산자는 비트 값들을 왼쪽으로 이동시킨 후에 오른쪽의 빈 공간에는 모두 0으로 채운다.

 >> 연산자는 비트 값들을 오른쪽으로 이동시킨 후에 왼쪽의 빈 공간에 양수라면 0으로, 음수라면 1로 채워줍니다.

 >>> 연산자는 비트 값들을 오른쪽으로 이동시킨 후에 부호와 상관없이 0으로 채워줍니다.

package Hello;

public class HelloWorld {
	public static void main(String args[]) {
		int a = 1; // 코드1
		a = a << 5; // 코드2
		System.out.println(a);
		a = a >> 3; // 코드3
		System.out.println(a);
		
		int b = -2147483648; // 코드4
		b = b >> 1; // 코드5
		System.out.println(b);
		
		int c = -2147483648; // 코드6
		c = c >>> 1; // 코드7
		System.out.println(c);
	}
}

 위의 예시는 어떤 값들을 출력할까요?

32
4
-1073741824
1073741824

 코드1에서 a에 1을 할당하므로 a = 0000 0000 0000 0000 0000 0000 0000 0001 (2) 가 됩니다.

 코드2에 의해 a는 왼쪽으로 5칸씩 비트가 이동하게 되고, 오른쪽의 파란 부분에는 0이 채워지고 위의 노란 부분에 해당하는 비트들은 사라지게 됩니다. 

 a = 0000 0000 0000 0000 0000 0000 0010 0000 (2)

 따라서, 현재 a는 10진법으로 32를 나타냅니다.

 코드3에 의해 a는 오른쪽으로 3칸씩 비트가 이동하게 되고, 양수이므로 왼쪽의 빨간 부분에 0이 채워지게 됩니다.

 a = 0000 0000 0000 0000 0000 0000 0000 0100 (2)

 따라서, 현재 a는 10진법으로 4를 나타냅니다.

 코드4에서 b에 -2147483648 을 할당하므로 b = 1000 0000 0000 0000 0000 0000 0000 0000(2) 가 됩니다.

 코드5에서 >> 연산은 음수 값은 왼쪽의 비는 부분을 1로 채우므로 b = 1100 0000 0000 0000 0000 0000 0000 0000(2) 가 되고, 10진수로 표현하면 -1073741824 가 됩니다.

 코드6에서 c = 1000 0000 0000 0000 0000 0000 0000 0000(2) 가 됩니다.

 코드7에서 >>> 연산은 부호에 상관 없이 왼쪽의 비는 부분을 0으로 채우므로 c = 0100 0000 0000 0000 0000 0000 0000 0000(2) 가 됩니다. 부호를 나타내는 맨 앞 코드가 0이 되어서 c는 양수가 되고 10진수로 표현하면 1073741824가 됩니다.

 

 비트 연산자는 따로 다른 포스팅에서 자세히 다뤄보겠습니다.


 

+ Recent posts