화공전산응용 4 차시
논리함수와 조건문/반복문
논리함수
논리함수는 매틀랩에서 중요한 함수로 여기선 find() 함수를 연습하게 된다. 일반 프로그램(밍) 언어에서 조건문/선택문은 단일 요소/스칼라의 조건만 선택하지만 행렬(Matrics) 기반 매트랩은 벡터/행렬(숫자 묶음)에 대한 조건을 (동시에)처리하는 논리함수를 사용하도록 만들었다.
1. 벡터(열, 행)에서 찾기
예를 들어 A=[1 5 6 3 4 2 7] 일 경우 여기서 ‘5’ 이상인 수를 확인하려면 보통은 반복문과 조건문을 써서 A 행렬의 요소(숫자 하나)를 하나 하나 조사해봐야 한다.
% Logical function - find() A=[1 5 6 3 4 2 7] ;
Over_5=[];
for k=1:length(A) if A(k)>=5
Over_5=[Over_5, k];
end end Over_5 find(A>=5)
>> find_for Over_5 =
2 3 7 ans =
2 3 7
A 행렬에서 5 이상인 수는 A 행렬에서 두번째, 세번째, 일곱번째에 있는 수/요소/값이다.
매틀랩에서 행렬을 처리하는 논리함수, find()를 쓰면 쉽게 숫자 묶음(벡터, 행렬)으로 처리한다.
키가 66 인치 이상이면 키 조건에서 합격이다.
>> h=[63 67 65 72 69 78 75];
>> pass=find(h>=66) pass =
2 4 5 6 7
그럼 합격생의 평균 키는?
>> mean(h(pass)) ans =
72.2000
합격생 중에서 가장 키 큰 사람은 응시자 중에서 가장 키 큰 사람과 같으니 문제가 되지 않고, 가장 작은 키로 합격한 응시자는?
>> min(h(pass)) ans =
67
67 인치로 합격한 사람이 가장 작은 합격생이다. 그럼 이 사람은 응시생 중에서 몇 번째인가?
min()는 출력인자를 두 개로 만들어야 Index No. 가 나온다.
>> [a,b]=min(h(pass)) a =
67 b = 1
>> pass(b) ans = 2
즉, 두번째 응시생이 가장 작은 키로 합격했다.
2. 조건이 2 개 이상인 경우
응시생의 나이는 다음과 같다. a=[18 19 18 20 36 34 12];
나이 조건은 18 세 이상 35 세 미만이다. 수학식으로는 18<=age<35 이지만 매트랩을 포함한 프로그래밍 언어에선 age>=18 and age<35 로 두 조건의 합(동시 만족)으로 표시해야 한다.
따라서 키 조건과 나이 조건이 모두 맞아야 하므로 합격생은?
h=[63 67 65 72 69 78 75]; a=[18 19 18 20 36 34 12];
A=[h; a];
pass=find(A(1,:)>66 & A(2,:)>=18 & A(2,:)<35)
pass =
2 4 6
A 행렬에는 행 별로 다른 자료가 들어 있다. 1 행에는 키가 2 행에는 나이가 …
>> A A =
63 67 65 72 69 78 75 18 19 18 20 36 34 12
이런 행 벡터 모음/묶음 자료/행렬은 fprintf()로 출력하면 열 벡터 자료 출력이 된다.
합격생의 응시 번호와 키 그리고 나이를 열 별로 출력시키려 한다. 앞서 만든 pass 변수에선 합격생의 응시 번호가 들어 있다. 이러한 자료는 모두 행 별로 되어 있고 이를 묶어 출력하면 열 별로 출력된다.
>> fprintf('%d 번 응시생은 키가 %d 인치이고 나이는 %d 세로 합격!\n',[pass;A(1,pass);A(2,pass)]) 2 번 응시생은 키가 67 인치이고 나이는 19 세로 합격!
4 번 응시생은 키가 72 인치이고 나이는 20 세로 합격!
6 번 응시생은 키가 78 인치이고 나이는 34 세로 합격!
다음처럼 B 로 별도 행렬을 만들어 처리해도 좋다.
>> B=[pass;A(1,pass);A(2,pass)]
B =
2 4 6 67 72 78 19 20 34
>> fprintf('%d 번 응시생은 키가 %d 인치이고 나이는 %d 세로 합격!\n',B) 2 번 응시생은 키가 67 인치이고 나이는 19 세로 합격!
4 번 응시생은 키가 72 인치이고 나이는 20 세로 합격!
6 번 응시생은 키가 78 인치이고 나이는 34 세로 합격!
fprintf()에서 열 별로 출력하므로 2, 67, 19, \n(줄 바꾸기) 순으로 출력하게 된다.
3. 논리함수 잘못 쓰는 예
find() 함수는 다른 프로그래밍 언어에서는 없는 것이고 많이 써오든 min(), max() 함수와 비슷하나 사용 방법이 달라 오류가 많이 나온다. 바른 사용법을 위해 오류를 정리하였다.
(1) 첫 번째 실수: find()에 몰두하여 max()를 같이 생각
max()는 최대값을 반환, find()는 조건에 맞는 번호(index)를 반환 max() 함수에서 순번(index)를 가져오려면 출력을 두 개로 해야 한다.
>> A=[33 55 66 48 56 65];
>> [maxn maxi]=max(A) maxn =
66 maxi = 3
>> a=find(A==max(A)) %무조건 인덱스만 찾는다 a =
3
>>a=max(A) %이러면 인덱스가 아니라 값을 찾는다 a =
66
행렬에서 max()는 열 별 최대값(과 인덱스)를 찾고 find()는 전체에서 인덱스만 찾는다(하나 또는 두 개)
>> B=[A;44 55 88 22 89 67; 55 88 89 67 79 82]
B =
33 55 66 48 56 65 44 55 88 22 89 67 55 88 89 67 79 82
>> [a b]=max(B) % 열 별로 최대값과 인덱스를 찾는다 a =
55 88 89 67 89 82 b =
3 3 3 3 2 3
>> find(B==max(B(:))) %전체 행렬에서 최대값 인덱스를 가져온다
ans = 9 14
>> [a b]=find(B==max(B(:))) %출력인자를 두 개 쓰면 행과 열 값을 가져온다 a =
3 2 b = 3
(2) 두 번째 실수는 행렬에서 열 별로 찾는 문제에서
몽땅다(‘:’)를 쓰는 문제이다. 열 별로 자료가 정리된 경우 1 열은 A(:,1), 2 열은 A(:,2)로 4 장 ‘행렬 다루기’에서 연습한 내용이다.
>> h=[63 67 65 72 69 78 75];
>> a=[18 19 18 20 36 34 12];
>> ha=[h;a]' ha =
63 18 67 19 65 18 72 20 69 36 78 34 75 12
>> pass=find(ha(:,1)>=66 & ha(:,2)>=18 & ha(:,2)<35) pass =
2 4 6
사실은 아래를 생각하면서 했기에 ‘열 별 비교’가 헷갈리게 되었다. max()등은 열 별로 처리하는데 find()는 전체를 처리하지만 열 별로 비교하면 전체 조건에 맞는 행 번호를 반환한다. 하나로 묶여있는 행렬에선 그렇지만 따로 떨어진 벡터에서 비교하면 어떠나 하는 마음이 있었다. 결과는 같다.
>> pass=find(h>=66 & a>=18 & a<35) pass =
2 4 6
find() 함수는 인덱스 번호만 가져온다(반환하다. 찾아낸다). 행렬에서 열 별 비교를 하면 행 번호만 가져오고 이 행 번호 간에 논리연산(&, | ~)된 결과가 나온다. 다른 벡터에서 작업해도 같다. 벡터에서 인덱스 번호를 가져오고 이 들간의 논리연산 결과가 출력된다.
지금 생각하니 당연한 것인데 수업 중엔 학생들 앞에서 키보드를 치면서 하다가 잘 되지 않으면 그 순간에 다른 생각들을 하게 되니 더 안되게 된다(몸과 맘은 처음 것을 하고 있는 도중에 머리에선 또 다른 몇 가지 생각을 하며 이 문제를 어떻게 해결할까 하니, 즉 뇌에서 멀티태스킹이 걸리는 데 멀티태스킹은 잘 되지 않는 것이 정답이다).
(3) 논리연산자가 달라요!
&& ||(broken bar)가 and, or 인데 안된다. 음 ‘&’ ‘|’이다. 매틀랩에선 하나이다. 다른 프로그램에선 대부분 두 개인데 …
조건문
1. if 문
(1) 조건이 만족하면(true, 1) 명령문(들)을 실행하고 아니면 실행하지 않고 지나간다.
if 조건 명령문 (명령문) ... ... ...
end
x > 2 ?
명령문(들) Yes
No
(2) (if)조건이 맞으면 명령문(들) 을 실행하고 그렇지 않으면(else) 다른 명령문(들)을 실행한다.
if 조건 명령문 명령문 ... ... ...
else
다른 명령문 다른 명령문 ... ... ...
end
(3) 조건 1이 맞으면 명령 1을 실행하고 아니면 다시 조건 2를 검사하여 맞으면 명령 2를 실행하고 둘 다 아니면 명령 3을 실행한다.
if 조건 1 명령문 1 elseif 조건 2 명령문 2 elseif 조건 3 명령문 3 ... ... ...
end
주의 :
(1) 'elseif' 는 붙여 쓴다. 프로그램 언어에 따라 띄어쓰기도 한다.
(2) 괄호는 없다. 일반적인 언어에선 조건은 ( ), 실행문은 { }에 넣어 범위를 표시한다.
x > 2 ?
명령문(들) Yes
No
다른 명령문(들)
조건 1 ? Yes 명령문(들) 1
No
명령문(들) 2
No
Yes
명령문(들) 3 조건 2 ?
다른 언어의 예;
if (x>2) { y = x .^ 2;
}
(3) 끝날때 'end'를 붙인다. 위와 같이 다른 언어에선 { } 로 끝을 알 수 있다.
switch_case 문
여러 조건에 따라 여러 곳으로 나누어 갈 때 사용한다. case 문에선 크다 작다 등을 사용하지 못하고 단지 정확히 같을 조건만 쓸 수 있다.
switch x case 1 y=x;
case 2 y=x*x;
otherwise y=0;
end
no==1 no==2
no==1 no==3
위 조건이 모두 맞지 않음
반복문
1. for 문
for 반복조건 반복할 명령문 1 반복할 명령문 2 ... ... ...
end
(exam) sum=0;
for i=1:10 sum=sum+i;
end sum
(설명) 1 에서 10 까지의 합을 구하는 프로그램
sum=0; % 누적값을 반복적으로 구하는데 초기값을 먼저 설정해야 한다.
for i=1:10 % 반복조건으로 i 가 1 에서 1씩(기본 증분) 증가하여 10이 될 때까지 반복
% 따라서 모두 (10 - 1) + 1 = 10 회 반복한다.
% for 문은 반복회수를 정하는 이외에 index를 증가(감소)시키며 이를
% 사용하는 것이 일반적이다.
% i=1:10 은 행렬에서 나오는 콜론 연산자가 아니다(i 는 벡터 X, 스칼라 O) sum=sum+i;% i 값은 증가하고 이를 sum 에 누적해가는 계산
end % for 문의 끝에 넣는다. 다른 프로그램에선 { }
sum % 계산된 sum 을 출력한다. ';'을 붙이면 출력하지 않는다.
2. while 문
while 반복조건
i=1:10
명령문(들) 반복 Yes
반복 No
실행문
(counter 값 증가) % for 문에서 쓰는 counter 를 여기선 만들어 사용한다.
반복(loop)을 빠져나갈 방법으로 조건문 있을 수 있다
(while 조건이 무조건 true, 1 이면 무한 반복에 빠지므로 여기서 빠져나갈 조건문이 필수) end
(exam 1) sum=0; i=0;
while i<=10 sum=sum+i;
i=i+1;
end sum
while 문에서 반복조건에 맞으면 반복 실행하고 조건에 맞지 않으면 반복실행을 중단한다.
실행 조건은 i<=10 이므로 i 가 증가하여 10이 될 때까지 반복하고 11이 되면 실행을 중단하고 다음 과정으로 넘어간다.
(exam 2) sum=0; i=0;
while 1 i=i+1;
if i>=11 break;
end sum=sum+i;
end sum
while 1 은 무한 반복문이다. '1'이 true 이므로 무한 loop로 들어간다.
i<=10
명령문(들) 조건 OK
조건 No
i>=11 명령문(들)
조건 OK
조건 No
실행문 중간에 빠져나갈 조건문이 있어야 한다. 반복하지 않고 빠져나갈 조건이 만족하면 break;
문을 써서 반복 loop 에서 벗어난다.
물론 while 에 반복조건이 있어도 중간에 빠져나갈 조건문을 쓸 수 있다.
하여튼 while 문에서 실수로 무한 반복 오류가 발생할 수 있으므로 for loop 를 쓰면 그러한 오류는 피할 수 있다.
위 예문에서 모두 10번 반복하나 반복 후의 index(또는 counter) 값은 for 문은 10, while 문은 11로 된다. while 문에서 i=11 까지 된 후 조건을 검사하여 중단하기에 i 값은 반복회수와 다르게 된다.
2015-06-25, 곽노태