Continuous Challenge

[Java의 정석_연습문제 풀이] Chapter3 연산자 본문

Study/Java의 정석

[Java의 정석_연습문제 풀이] Chapter3 연산자

응굥 2019. 10. 7. 14:41
728x90
728x90

[3-1] 다음 연산의 결과를 적으시오.


답 : 

1) 6
-> '1+x << 33'는 x의 값이 2이므로 '1+2<<33'가 된다. 덧셈연산자보다 쉬프트연산자가 우선순위가 낮으므로 '3<<33'이 된다. int는 32bit이므로 33번 쉬프트하지않고 1번만 쉬프트한다. '3<<1'은 3에 '2의 1제곱'인 2를 곱하는 것과 같은 결과를 얻으므로 '3*2'가 되어 6을 얻게 된다.

2) true

3) 13

4) 5

-> 이전의 식에서 x의 값이 1증가하였으므로 3에 2를 더한 5가 결과가 된다.

5) false

6) 2

7) 5

8) 66

-> c의 값이 'A'이므로 'A'+1이 되고, 이항연산자의 성질(int보다 작은 타입은 int로 변환 후 연산)때문에 'A'는 문자코드 값인 65로 변환되어 '65+1'을 수행하여 66을 결과로 얻는다.

9) B

-> 단항연산자인 '++'은 이항연산자와 달리 int보다 작은 타입도 형변환을 하지 않는다.(이항연산자는 연산을 위해 '피연산자 스택(operand stack)'을 사용하는데 이 과정에서 형변환이 발생하는 것이다. 반면에 단항연산자인 증가연산자 '++'은 '피연산자 스택'을 사용하지 않으므로 형변환도 발생하지 않는다.) 그래서 println은 변수c를 숫자(int)로 출력하는 것이 아니라 문자로 출력한다. 변수 c에 저장된 문자가 'A'(실제로 저장된 것은 'A'의 문자코드인 65)이므로 문자코드의 값이 1증가되어 66('B'의 문자코드)이 변수 c에 저장된다. 

 변수 c에 저장된 것은 문자코드, 즉 정수값이다. println은 이 값을 타입에 따라 어떻게 출력할지를 결정한다. 만일 문자타입이면 저장된 값(문자코드)에 해당하는 문자를 출력하고 숫자라면 숫자로 출력한다.

10) B

11) C



[3-2] 아래의 코드는 사과를 담는데 필요한 바구니 수를 구하는 코드이다. 만일 사과의 수가 123개이고 하나의 바구니에는 10개의 사과를 담을 수 있다면, 13개의 바구니가 필요할 것이다. (1)에 알맞은 코드를 넣으시오.


답 : (1) numOfApples/sizeOfBucket + (numOfApples%sizeOfBucket > 0 ? 1 : 0)



[3-3] 아래는 변수 num의 값에 따라 '양수', '음수', '0'을 출력하는 코드이다. 삼항 연산자를 이용해서 (1)에 알맞은 코드를 넣으시오. 

(Hint. 삼항 연산자를 두 번 사용하라.)


답: (1) num >= 0 ? (num == 0 ? "0" : "양수") : "음수"

 num > 0 ? "양수" : (num < 0 ? "음수" : "0")


[3-4] 아래는 변수 num의 값 중에서 백의 자리 이하를 버리는 코드이다. 만일 변수 num의 값이 '456'이라면 '400'이 되고, '111'이라면 '100'이 된다. (1)에 알맞은 코드를 넣으시오. 


답 : (1) num/100 * 100



[3-5] 아래는 변수 num의 값 중에서 일의 자리를 1로 바꾸는 코드이다. 만일 변수 num의 값이 333이라면 331이 되고, 777이라면 771이 된다. (1)에 알맞은 코드를 넣으시오.


답 : (1) num/10*10 + 1



[3-6] 아래는 변수 num의 값보다 크면서도 가장 가까운 10의 배수에서 변수 num의 값을 뺀 나머지를 구하는 코드이다. 예를 들어, 24의 크면서도 가장 가까운 10의 배수는 30이다. 19의 경우 20이고, 81의 경우 90이 된다. 30에서 24를 뺀 나머지는 6이기 때문에 변수 num의 값이 24라면 6을 결과로 얻어야 한다. (1)에 알맞은 코드를 넣으시오. (Hint. 나머지 연산자를 사용하라.)


답 : (1) ((num+10)*10) % num 

10 - num%10



[3-7] 아래는 화씨(Fahrenheit)를 섭씨(Celcius)로 변환하는 코드이다. 변환공식이 'C = 5/9 * (F-32)'라고 할 때, (1)에 알맞은 코드를 넣으시오. 단, 변환 결과값은 소수점 셋째자리에서 반올림해야한다. (Math.round()를 사용하지 않고 처리할 것)


답 : (1) (int)((5/9f * (fahrenheit - 32))*100+ 0.5) / 100f

-> 해설 : 먼저 화씨를 섭씨로 바꾸는 공식은 이다 의 결과 '5/9f * (fahrenheit - 32)' . 5/9 는 0이기 때문에 두 피연산자 중 어느 한 쪽을 반드시 float나 double로 해야만 실수형태의 결과를 얻을 수 있다 그래서 정수형 리터럴인 9대신 float타입의 리터럴인 9f를 사용하였다.


수점 셋째자리에서 반올림을 하려면 다음의 과정을 거쳐야한다.

1. 값에 100을 곱한다. 

-> 37.77778 * 100 

2. 1의 결과에 0.5를 더한다. 

-> 3777.778 + 0.5 → 3778.278

3. 2의 결과를 int타입으로 변환한다. 

-> (int)3778,278 → 3778 

4. 3의 결과를 100f로 나눈다. (100으로 나누면 소수점 아래의 값을 잃는다.) 

-> 3778 / 100f → 37.78




[3-8] 아래 코드의 문제점을 수정해서 실행결과와 같은 결과를 얻도록 하시오.


답 : 

* 이항연산은 두 피연산자의 타입을 일치시킨 후 연산을 수행한다는 것, 그리고 int보다 작은 타입은 int로 자동변환한다는것은 반드시 기억하고 있어야하는 중요한 내용이다. *


line 5 : byte c = a + b; => byte c = (byte)(a+b);

line 7 : ch = ch + 2; => ch = (char)(ch+2);

line 8 : float f = 3/2; => float f = 3/2f;

line 9 : long l = 3000 * 3000 * 3000; => long l = 3000 * 3000 * 3000L;

-> int * int * int 의 결과는 int이므로 int 타입의 최대값인 약 2*10의 9제곱을 넘는 결과는 오버플로우가 발생하여 예상한 것과는 다른 값을 얻는다. 그래서 피연산자 중 적어도 한 값은 long 타입이어야 최종결과를 long타입의 값으로 얻기 때문에 long타입의 접미사 'L'을 붙여서 long타입의 리터럴로 만들어줘야 한다.

line 12 : boolean result = d==f2; => boolean result = (float)d==f2;

-> 비교연산자도 이항연산자이므로 연산 시에 두 피연산자의 타입을 맞추기 위해 형변환이 발생한다. 그래서 double과 float의 연산은 double과 double의 연산으로 자동형변환 되는데, 실수는 정수와 달리 근사값으로 표현을 하기 때문에 float를 double로 형변환했을 때 오차가 발생할 수 있다. 

 그래서 float값을 double로 형변환하기보다는 double값을 유효자리수가 적은 float으로 형변환해서 비교하는 것이 정확한 결과를 얻는다.



[3-9] 다음은 문자형 변수 ch가 영문자(대문자 또는 소문자)이거나 숫자일 때만 변수b의 값이 true가 되도록 하는 코드이다. (1)에 알맞은 코드를 넣으시오. 


답 : (ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z') || (ch >= '0' && ch <= '9')


[3-10] 다음은 대문자를 소문자로 변경하는 코드인데, 문자 ch에 저장된 문자가 대문자인 경우에만 소문자로 변경한다. 문자코드는 소문자가 대문자보다 32만큼 더 크다. 예를 들어 'A'의 코드는 65이고 'a'의 코드는 97이다. (1)~(2)에 알맞은 코드를 넣으시오.


답 : 
(1) ch >= 'A' && ch <= 'Z'
(2) (char)(ch+32)


728x90
728x90
Comments