함수에 대해서 설명한 이전 포스트에서 함수 정의부에 명시된 입력 변수의 개수보다 적은 입력변수를 함수에 넘겨주는 경우 못받은 변수는 생성이 되지 않으므로 이를 따로 처리해야 한다고 하였다. 그렇다면 함수 내부에서 입출력 변수의 개수를 어떻게 알아낼 수 있을까? 이 작업을 위해서 nargin변수와 nargout변수가 마련되어 있다. 이 변수들은 모두 정수값을 가지며, nargin변수는 호출된 함수 내부에서 그 함수로 인가된 입력 변수의 개수값을 가지고 nargout 변수는 출력 변수의 개수를 가진다. 이들 변수값을 이용하여 여러 가지 입출력 방법에 대해서 대처를 할 수 있다. 앞에서 예를 든 mimo()함수를 다음과 같이 수정해 보자.


1 : function [y1,y2]=mimo2(x1,x2,x3)
2 : % function [y1,y2]=mimo(x1,x2,x3)
3 : % y1은 입력변수들의 합
4 : % y2는 입력변수들의 곱
5 : if (nargin==1)
6 :     y1=x1;
7 :     y2=x1;
8 : elseif (nargin==2)
9 :     y1=x1+x2;
10:     y2=x1*x2;
11: elseif (nargin==3)
12:     y1=x1+x2+x3;
13:     y2=x1*x2*x3;
14: else
15:    y1 = 0;
16:    y2=0;
17: end


이 수정된 함수에서 5번 줄과 8번 줄 그리고 11번 줄에서 nargin변수가 사용이 되었다. nargin==1이 참이라면, 즉 입력변수가 하나라면 6번 줄과 7번 줄을 수행시킨다. nargin==2이 참이라면, 즉 입력변수가 두개라면 9번 줄과 10번 줄을 수행시킨다. nargin==3이 참이라면, 즉 입력변수가 세 개라면 12번 줄과 13번 줄을 수행시킨다. 마지막으로 모든 경우가 거짓이라면, 즉 입력 변수가 없다면 15, 16번 줄을 수행시킬 것이다. 입력변수가 4개 이상이라도 else 문에 걸려서 15,16번 줄이 수행된다.


>> [x,y]=mimo2()
x = 0
y = 0
>> [x,y]=mimo2(11)
x =  11
y =  11
>> [x,y]=mimo2(11,22)
x =  33
y =  242
>> [x,y]=mimo2(11,22,33)
x =  66
y =  7986
>> [x,y]=mimo2(11,22,33,44)
x = 0
y = 0


연습삼아서 이 mimo2()함수를 switch-case문을 이용하여 수정해 보기 바란다.


'프로그래밍언어.Lib > MATLAB' 카테고리의 다른 글

MATLAB의 함수 m파일  (0) 2015.07.16
MATLAB의 break, continue 명령  (0) 2015.07.16
MATLAB의 반복문 while ~ end  (0) 2015.07.14
MATLAB의 반복문 for ~ end  (0) 2015.07.14
MATLAB의 조건문 switch ~ case ~ end  (0) 2015.07.13
Posted by 살레시오
,

 스크립트 m파일과 구별되는 다른 형태의 파일로서 함수(function) m파일이 있다. 지금까지 자주 사용해왔던 sin(), cos(), exp()같은 함수를 생각해 보면 사용자는 입력값을 이들 함수에 넘겨주고, 예를 들어 sin(pi)명령은 pi라는 값을 sin()함수에 넘겨주고 그 결과값 0을 얻게 된다. 내부적으로 어떠한 계산 과정이 있는 지는 일반 사용자는 알 필요가 없고 단지 입력에 대한 결과값을 얻을 뿐이다. 이와 같이 미리 정의된 함수 외에 사용자만의 함수를 작성할 수도 있다.


 함수 m파일은 입력 값과 출력 값이 존재하며 입력 변수를 받아서 특정한 기능이나 계산 등을 수행한 다음 그 결과 값을 반환하는 기능을 한다. 스크립트 m파일의 경우 생성된 변수들이 작업 공간에 위치하는 것과는 대조적으로 함수 m파일은 함수 내에서 사용된 변수들이 작업 공간과는 별도의 메모리 공간을 사용하며 함수의 수행이 끝나면 그 메모리 공간도 사라진다. 단지 출력 값만을 그 함수가 호출된 곳으로 반환시켜줄 뿐이다.

다음의 예제를 입력하여 보자.


function Y = flipud(X)
   [m,n] = size(X);
   Y = X(m:-1:1,:);


그리고 이 파일을 ‘flipud.m'으로 저장하자. 이 함수는 행렬 x를 받아서 행들의 순서를 역순으로 바꾼 후 출력하는 기능을 하는 함수이다. 이제 명령창에서 다음과 같이 명령을 내려보자.


>>A=rand(3,2) 󰎠
A =
0.0187 0.9737
0.3107 0.5865
0.7713 0.6441

>>B=flipud(A) 󰎠
0.7713 0.6441
0.3107 0.5865
0.0187 0.9737


위에서 입력 행렬 A의 행의 순서가 바뀌어서 반환된 것이 B에 저장됨을 알 수 있다. 또한 함수 내부에서 사용된 변수 m,n은 작업 공간에 나타나지 않음도 변수창에서 확인할 수 있다. 작업 공간에는 출력변수 B만이 생성되는 것이다.


 함수 m파일은 첫 번째 줄은 이 M파일이 함수라는 것을 나타내는 키워드 'function' 과 출력 변수, 함수 이름, 입력 변수 등으로 구성되며 문법은 다음과 같다.


function [y1, y2, …] = fname(x1, x2, …)


함수의 이름 fname은 m파일의 이름과 되도록이면 같도록 해야 한다. 만약 다르면 m파일의 이름이 우선하게 된다. 함수의 입출력 변수는 여러 개일 수도 있고 하나도 없을 수도 있다. 또한 함수의 정의부에 선언된 입출력 변수보다 적은 수의 변수로 함수를 호출할 수 있지만 더 많은 수의 입출력 변수를 지정하면 에러가 발생하게 된다. 다음의 예를 보자.


function [y1,y2]=mimo(x1,x2,x3)
% function [y1,y2]=mimo(x1,x2,x3)
% y1은 입력변수들의 합
% y2는 입력변수들의 곱
y1=x1+x2+x3;
y2=x1*x2*x3;


이 함수는 입력이 3개이고 출력이 2개인 함수이며 출력 y1은 입력들의 함을, y2는 입력들의 곱을 계산한다. 함수 정의부 밑에 ‘%’로 시작하는 문장들은 주석문으로서 M파일에서 '%'뒤에 오는 것들은 무시하며 실행하지 않으므로 이 기호 뒤에 설명문을 위치시키면 된다. 함수의 선언문과 첫 번째 실행문 사이의 주석문은 단순한 주석문이 아니라 명령창에서 help명령을 수행시켰을 때 보여주는 문장들이다. 명령창에서 다음을 수행해 보자.


>>help mimo 󰎠
function [y1,y2]=mimo(x1,x2,x3)
y1은 입력변수들의 합
y2는 입력변수들의 곱


이제 이 함수를 실행시켜 보자. 함수 정의부에서 출력 변수는 두 개로 지정이 되었지만 함수를 호출할 때는 출력변수를 0개, 1개, 2개 모두 지정할 수 있으며 3개 이상을 지정하면 에러가 발생한다.


>>mimo(3,4,5)
y1 =
12

>>y1=mimo(3,4,5)
y1 =
12

>>[y1,y2]=mimo(3,4,5)
y1 =
12
y2 =
60

>>[y1,y2,y3]=mimo(3,4,5)
-----------------------------------
* MATLAB 디버그 정보 (오류 발생) *
-----------------------------------
파일 이름 : C:\MATLAB_MFILES\mimo.m
라인 번호 : 1 --> function [y1,y2]=mimo(x1,x2,x3)
오류 내용 : 함수의 입출력 갯수가 올바르지 않습니다.


위에서 알 수 있듯이 출력 변수를 지정하지 않으면 첫 번째 출력 변수만을 화면에 보여준다. 그리고 출력 변수를 하나만 지정하면 두 번째 출력변수는 반환되지 않게 된다.

입력 변수도 아예 지정하지 않거나 한 개나 두 개만 입력할 수 있지만 함수 내에서 넘겨받지 않은 변수는 생성되지 않게 되므로 함수 실행 시 에러를 발생하게 된다.


>> mimo(3,4)
-----------------------------------
* MATLAB 디버그 정보 (오류 발생) *
-----------------------------------
파일 이름 : C:\MATLAB_MFILES\mimo.m
라인 번호 : 5 --> y1=x1+x2+x3; %...
오류 내용 : x3라는 변수나 함수가 없습니다. 이름이 맞는지 확인하십시요.


위의 경우는 세 번째 입력변수를 넘겨주지 않았으므로 mimo함수 내부적으로 x3라는 변수 자체가 없어서 덧셈을 수행하지 못하게 되는 것이다. 즉 적은 수의 입력 변수를 넘겨주는 것은 문법적으로 허용이 되지만 넘겨받지 못한 변수를 생성하기 위한 추가적인 실행문이 필요하게 된다. 이에 대해서는 다른 포스트에서 자세히 설명하겠다.





Posted by 살레시오
,

 반복문 수행 시 어떤 경우에는 수행 중이던 반복문을 중단하고 빠져 나와야 하는 경우가 발생할 수도 있다. break 문은 for 구문이나 while 반복문 내에서 사용되며 반복문을 빠져 나오게 만드는 명령어이다. 반복문은 한번 시작하면 반복 변수가 마지막 값을 가질 때까지 반복을 수행해야 하는데 break 명령은 그 위치에서 반복을 중단하고 반복문을 빠져 나오게 만든다. 다음의 예를 살펴보자.


for k=0:10
   for n=0:10
       if (n==5)
           break
   end
   end
end


이 예에서 첫 번째 for 문은 k가 0부터 10까지 수행되고, 각각의 k값에 대해서 안쪽의 for 루프를 만나 n이 0부터 10이 될 때까지 수행을 해야 하지만 n이 5일 때에는 if의 조건이 참이 되므로 break 문을 만나게 된다. 이 때, 안쪽 루프를 탈출하게 된다. 다시 바깥쪽의 for 문을 돌게 되는 것이다. 이 중첩된 루프가 끝났을 때엔 k에는 10이, 그리고 n에는 5가 입력되어 있다.


 또 다른 예를 들어보자. 1과 자기 자신으로만 나누어지는 2보다 큰 양의 정수를 소수(prime number)라고 한다. 주어진 정수 n이 소수인가 아닌가를 판별하는 가장 간단한 방법으로는 n을 2,3,4,…,n-1로 나누어지는지 차례로 검사하는 것이다. 그 모든 수에 대해서 나누어지는 수가 (즉 나머지가 0인 수가) 하나도 없다면 n은 소수일 것이고 그렇지 않다면 n은 소수가 아닌 것이다. 나머지를 구하는 함수는 rem()함수이다. rem(m,n)은 m을 n으로 나눈 나머지를 반환하여 준다. 다음 프로그램을 살펴보자.


1 : n=input('양의 정수를 입력하시오');
2 : for k=2:n-1
3 :     m=rem(n,k);
4 :     if m==0 break, end
5 : end
6 : if m==0
7 :     sprintf('%d는 소수가 아님.',n)
8 : else
9 :     sprintf('%d는 소수.',n)
10: end


사용자로부터 숫자 n을 입력받아서 2번 줄의 for문으로 인해 2부터 n-1까지 숫자로 차례로 나눠서 그 나머지를 구한다. 만약 중간에 나머지가 0인 경우가 발생한다면 더 이상 반복문을 수행할 필요가 없는 것이다. 따라서 이 경우를 4번 줄에서 검사하여 바로 반복문을 빠져나오게 된다. 그리고 6번 줄에서 만약 m이 0이라면 어떤 숫자로부터 나눠진 경우가 발생한 것이므로 소수가 아니라는 판정을 내리고 그렇지 않은 경우 소수라는 판정을 내리게 되는 것이다. (참고로 소수의 리스트를 구할 수 있는 matlab 함수로는 primes()함수가 있다.)

 continue 명령은은 for문이나 while문 안에서 쓰이며 루프의 맨 처음으로 제어 흐름을 바꿔 주는 역할을 한다. 즉 while에서는 조건을 비교하는 부분으로, 그리고 for에서는 반복 변수값을 변화시켜서 for문 바로 다음의 명령문으로 흐름을 바꿔주는 역할을 한다. 다음의 예를 살펴보자.


1: clear all
2: for n=1:10
3:     tmp=n^3;
4:     if (n==5) continue, end
5:     k(n) = tmp;
6: end


이 예에서 k의 값이 변하는 추이를 살펴보자. n이 5가 되기 전에 k에 1, 8, 27, 64의 값을 저장한다. 그런데 n==5가 참이 되면 continue 문이 실행되고, 즉시 n=6으로 되고 3번 줄로 되돌아 가게 된다. 그러므로, 벡터 k(5)에는 125가 저장이 되지 않고 다음 반복문으로 넘어가게 된다.




Posted by 살레시오
,

 for 반복문이 정해진 횟수만큼의 반복 수행을 한다면 while 명령은 명령군을 무한 번까지 반복할 수 있다. while 뒤의 조건이 참이면 속한 명령어들을 계속 반복 수행하게 된다. 사용법은 다음과 같다.


while 조건문
   명령문1
   명령문2
   ⋮
end


1부터 100까지의 합을 구하는 프로그램을 while문을 이용하여 작성해보자. 다음 프로그램을 ‘whilex1.m'으로 저장하고 명령창에서 수행해 보자.


clear all
n=1;
m=0;
while (n<=100)
   m+=n;
   n++;
end


여기서 n++ 는 n=n+1 과 같고 m+=n 은 m=m+n과 같다.


 다른 예로서 n이 양의 정수일 때 n! 이 106 을 넘는 가장 작은 n을 구하는 프로그램을 while문을 이용하여 작성해보면 다음과 같다.


1: clear all
2: n=1;
3: while prod(1:n)<1e6
4:     n++;
5: end


3번 줄에서 n!이 106보다 작으면 n을 1증가시키고 (n++) 다시 3번 줄의 조건을 수행하는데 만약 n!이 106보다 크면 바로 프로그램이 종료가 된다. 따라서 프로그램의 수행이 끝난 시점에 변수 n에 저장된 수가 106을 넘는 가장 작은 정수가 되는 것이다.


 또 다른 예제를 들면 다음과 같다. 편의상 각각의 줄 앞에 번호를 붙였다.


1: clear all
2: num=0; EPS=1;
3: while (1+EPS)>1
4:     EPS=EPS/2;
5:     num=num+1;
6: end
7: disp(EPS)


1번 줄에서 작업 공간의 모든 변수를 제거하고 2번 줄에서 변수들을 초기화 시켰다. 그리고 3,4,5번줄은 EPS가 컴퓨터가 더 이상 구분할 수 없이 작아질 때까지 EPS를 2로 계속 나누면서 반복하는 것이다. 이것은 내부변수 eps를 구하는 알고리듬을 구현해 본 것이다. eps는 MATLAB이 표현할 수 있는 가장 작을 수라고 앞에서 소개했었다. 일반적으로 실수를 표현하는데 있어서 한정된 비트수를 쓰기 때문에 기계 내부적으로 표현할 수 있는 가장 작은 수가 존재한다.


 while문의 조건문은 결과가 스칼라일수도 있으나 일반적으로 행렬일 수도 있다. 이 경우 행렬의 ‘모든’ 요소가 참(0이 아닌값)일 경우에 반복문을 수행하게 된다. 즉 하나라도 0인 요소가 있으면 반복문의 수행을 중단하게 된다. 다음 예제를 입력하고 ‘whilex3.m'으로 저장한 후 실행시켜 보라.


a = ones(2,2);
b = 4*a;
while b
   b = b-a;
end


처음의 두 실행문에서 행렬 a와 b는 다음과 같이 각각 생성된다.

그리고 처음의 while문에서 행렬 b의 모든 요소는 0이 아니므로 반복문이 수행되고 그 결과로서 행렬 b는 다음과 같이 변하게 된다.

그 다음 아직도 행렬 b의 모든 요소는 0이 아니므로 반복문이 수행되고 그 결과로서 행렬 b는 다음과 같이 변하게 된다.

그 다음 다음번의 수행에서 행렬 b는 다음과 같이 변하게 되고

이제는 행렬b의 모든 요소가 0이므로 반복문을 수행하지 않고 while문을 빠져 나오게 된다.



Posted by 살레시오
,

 MATLAB에서는 반복문을 위해서 for 와 while 명령이 있다.여기에서는 for문에 대해서 알아보겠다. for 문 다음에 나오는 변수가 초기 값에서 조건문에서 제시한 최종 값으로 증가값 만큼씩 변하는 동안에 for ~ end 사이의 명령들을 반복 수행한다.

for 반복변수 = 초기 값(:증가값):최종값
   명령문 1
   명령문 2
   ⋮
end


for 이후에 지정된 반복 횟수와 인덱스에 따라 반복실행을 한다. 예를 들어 반복변수를 k = 10:-1:1 으로 지정하면 변수 k는 10 부터 1씩 감소해 나가는 형식으로 10번을 반복하여 수행문을 실행한다. 증가값은 생략이 가능하고, 증가값을 생략하면 기본적으로 1씩 증가하게 된다. 즉 콜론(:) 연산자의 사용법이 for 문의 반복 변수를 지정하는데 그대로 쓰이는 것이다. 단 콜론 연산자로 인하여 벡터가 생성되어 반복 변수에 저장되는 것은 아니고 반복문 안에서 순차적으로 변하는 스칼라 값이 된다.


 다음 예제는 1부터 100까지의 합을 구하는 것이다.


m=0;
for n=1:100
   m = m+n;
end


지금 소개하는 for문 외에도 앞으로 소개하는 모든 명령어들은 명령창에서도 그대로 사용할 수 있다. 명령창에서 다음과 같이 입력해 보라.


>>for n=1:10 x(n)=sin(n*pi/10); end


이 예는 반복문의 변수 n을 변수 x의 인덱스로 사용하여 벡터 x를 생성하는 예제이다. 물론 위의 예와 동일한 일을 수행하는 것은 다음과 같다.


>>n=1:10; x=sin(n*pi/10)


이와  같이 matlab의 벡터나 행렬을 다루는 명령을 이용해서 수행을 하는 것이 for 반복문을 사용하는 것보다 훨씬 더 효율적이고 시간적으로도 이득이 있다. 따라서 fo r반복문을 사용하기 전에 동일한 문제를 벡터나 행렬로서 푸는 방법이 있는지 한 번 생각해봐야 한다. 처음에 나왔던 1부터 100까지의 합을 구하는 방법은 sum()함수를 이용하여 다음과 같이 간단히 해결될 수 있다.


>> k=sum(1:100)


 for 반복문은 반복 변수가 최종값이 이르렀을 때 종료하게 된다. 하지만 반복문 내부에서 이 반복 변수값을 임의로 조정하여 반복 수행을 종료할 수는 없다. 다음 예제를 'forex1.m'이라고 저장한 후 수행시켜 보자.


for n=1:10
   x(n) = sin(n*pi/10);
   n=10;
end


결과는 변수 x는 크기 10인 벡터로 생성된다. 즉 이는 반복문 내부에서 반복 변수를 임의로 조정할 수 없다는 의미이다.


 반복변수를 콜론 연산자로 생성하는 것이 기본적인 사용법이긴 하나 임의의 벡터나 행렬로도 지정해 줄 수 있다. 다음의 예를 입력한 후 ‘forex2.m'으로 저장하자.


m=1;
for n=[2 3 5 7 11 13 17 19]
   m = m*n;
end


위의 프로그램을 수행한 결과이다.


>>forex2
>>n
19
>>m
9699690


반복문이 종료되는 시점에서는 반복변수 n은 지정한 벡터의 마지막 값을 가지고 변수 m은 이들을 모두 곱한 값을 가지게 된다. 즉 반복문의 첫 번째 수행에서는 n=2값을 가지고 두 번째 수행에서는 n=3값을 가지고 세 번째 수행에서는 n=5값을 가지고 … 마지막 수행에서는 n=19값을 가지게 된다.


 for 반복문은 중첩해서도 사용할 수 있다. 다음의 예를 'forex3.m'으로 저장하고 수행해 보자.


clear all
for n=1:5
   for m=5:-1:1
       A(n,m)=n^2+m^2;
   end
end
disp(A)


이 예제에서 첫줄의 'clear all'명령은 현재 작업공간에 잡혀있는 모든 변수를 메모리에서 제거하라는 명령어이다. 그리고 마지막 줄의 disp()함수는 입력값을 화면에 출력하라는 함수이다. 명령창에서 위의 프로그램을 실행한 결과는 다음과 같다.


>>forex3
2.0000 5.0000 10.0000 17.0000 26.0000
5.0000 8.0000 13.0000 20.0000 29.0000
10.0000 13.0000 18.0000 25.0000 34.0000
17.0000 20.0000 25.0000 32.0000 41.0000
26.0000 29.0000 34.0000 41.0000 50.0000


보통은 for문에서 반복적으로 생성되는 변수는 미리 최대 크기로 생성시켜 놓는 것이 좀 더 효율적이다. 예를 들어 바로 이전 예제에서 행렬 A는 반복수행이 될 때마다 기존의 크기에서 1씩 늘어나게 된다. 처음 수행때는 1×5 크기였다가 다음 수행 때는 2×5크기로 늘어나고 … 마지막 수행 때에는 5×5크기로 늘어난다. 이렇게 벡터나 행렬의 크기를 그때그때 ‘늘리는’ 것은 메모리를 많이 사용하며 또한 수행시간 면에서도 비효율적이다. 따라서 for문의 앞에 A=zeros(5,5) 또는 A(5,5)=0 명령으로 미리 A행렬을 5×5크기로 생성시켜 놓고 반복문에 진입하는 것이 조금 더 효율적이다. 여기에 나오는 예제와 같이 아주 작은 프로그램에서는 별로 차이가 없겠지만 반복문 내에서 생성되는 행렬이 수천에서 수만의 요소를 갖는 것이라면 얘기가 달라질 것이다.


 마지막으로 어떤 실수 행렬이 있을 때 그 행렬의 양수의 요소들의 개수, 0의 개수 그리고 음수의 요소들의 개수를 구하는 프로그램을 for문을 이용하여 만들어 보자.


1: clear all
2: a=rand(100,1)*10-5; %-5와 5사이의 임의의 실수 생성
3: nm=0; np=0; nz=0;
4: for i=1:100
5:     if a(i)<0 nm=nm+1;
6:     elseif a(i)>0 np=np+1;
7:     else nz=nz+1;
8:     end
9: end


2번 줄을 보면 rand()함수를 이용하여 난수를 발생시키는데 이 함수는 0과 1사이의 임의의 실수를 발생시키므로 2번줄과 같이 처리하여 -5와 5사이의 임의의 실수를 발생시켜서 변수 a에 저장하도록 하였다. 그리고 5번줄에서 음수이면 nm을 하나 증가시키고, 6번줄에서 양수이면 np를 하나 증가시키고 마지막으로 이도저도 아니면 7번줄에서 nz를 하나 증가시키도록 하여서 행렬 a의 모든 요소를 검사하도록 하였다.


 물론 이 경우에도 for문을 쓰지 않고 예를 들면 다음과 같이 간단하게 같은 일을 수행하는 프로그램을 작성할 수 있을 것이다.


1: clear all
2: a=rand(100,1)*10-5; %-5와 5사이의 임의의 실수 생성
3: nm = sum(a<0)
4: np = sum(a>0)
5: nz = 100-nm-np


3번 줄을 보면 a<0은 행렬a와 같은 크기는 가지는 행렬로서 0보다 작은 요소가 있는 자리에 1이 그렇지 않은 자리에는 0이 위치하므로 이들을 모두 합하며 0보다 작은 요소의 개수가 구해질 것이다. 4번 줄도 같은 원리이다. 앞에서도 언급한바 있지만 프로그램을 코딩할 때 MATLAB의 행렬을 다루는 함수나 내부 함수를 이용하여 보다 효율적으로 작성하는 것을 항상 생각해 볼 필요가 있다.



Posted by 살레시오
,

 조건문을 처리하는 두 번째 방법은 switch-case구문을 사용하는 것이다. if문과는 달리 swtich-case구문은 하나의 변수에 대해서 여러 가지 경우를 처리해야 되는 경우에 좀 더 유용하다. 문법은 다음과 같다.


switch 표현식
   case 대조값1
       명령집합1
   case 대조값2
       명령집합2
   ː
   otherwise
       명령집합m
end


동작 순서는 다음과 같다. switch문 다음에 오는 표현식의 값을 계산한 후에 그 값이 대조값1 과 같으면 명령집합1을 수행한 후 end 다음으로 이동한다. 대조값1과 다르면 대조값2와 비교하여 같으면 명령집합2를 수행한 후 end 다음으로 이동한다. 모든 case문 뒤의 대조값들과 다른 경우 otherwise뒤의 명령집합m을 수행하게 된다.


 이 swtich-case구문을 사용하여 이전 포스트의 2차 방정식 근의 종류를 판별하는 프로그램을 작성해 보자. 여기서 switch문 뒤의 표현식에서 sign()함수를 사용할 것인데 sign(D) 함수는 입력 D값이 음수이면 -1을, 0이면 0을 그리고 양수이면 +1을 반환하는 함수이다. 즉 부호(sign)를 판별하는 함수인 것이다. 다른 부분은 앞의 경우와 크게 다른 것은 없고 다만 8번줄에서 시작되는 switch-case구문의 사용법에 유의하라.


clear all
a=input('x^2의 계수:')
b=input('x의 계수:')
c=input('상수 계수:')
D = b^2-4*a*c;
s = roots([a b c]);
sprintf('방정식 %.2fx^2+%.2fx+%.2f=0은 ',a,b,c)
switch sign(D)
   case 1
       sprintf('서로 다른 실근') %(1)
   case 0
       sprintf('중근') %(2)
   otherwise
       sprintf('허근')%(3)
end
s


switch문에서 sign(D)값을 계산한 후 그 값이 1이면 (1)을 수행하고 제어 흐름이 end 밖으로 이동한다. sign(D)값이 0이면 (2)를 수행하고 제어 흐름이 end 밖으로 이동한다. sign(D)값이 0도 아니고 1도 아니면 (3)을d 수행한 후 end 밖으로 이동한다.



Posted by 살레시오
,

 많은 경우에 있어서 명령어들은 어떤 관계의 참, 거짓 여부를 따져서 조건부로 실행시켜야 되는 경우들이 있다. 여기에서는 이런 경우에 사용되는 if문과 switch문에 대해서 살펴보겠다.

 if문의 가장 간단한 사용법은 다음과 같다.


if 조건문
   명령집합
end


여기서 조건문이 참(0이 아닌값)이면 if명령어와 end 사이의 명령집합을 실행시키고 거짓(0)이면 명령집합을 실행시키지 않는다. 간단한 예제를 작성해 보자. 사과를 구입하는데 사과 하나에 500원이고 만약 사과를 10개 이상 구입을 하면 가격의 20%를 깎아준다고 한다. 사과의 개수를 입력받아서 가격을 구하는 프로그램은 다음과 같이 작성할 수 있다.


clear all
n = input('사과의 개수는?');
cost = n*500;
if (n>=10)
   cost = 0.8*cost;
end
sprintf('사과의 개수는 %d개이고 가격은 %d입니다.',n,cost)


둘째 줄에서 input()함수를 이용하여 사과의 개수를 입력받아 변수 n에 저장하였고 네째 줄에서 입력받은 개수가 10보다 크거나 같은지를 조건검사한다. 그래서 10이상이면 계산된 가격에 0.8을 곱해서 가격을 다시 계산한 후 일곱 번째 줄에서 가격을 화면에 표시하게 된다.


 위의 프로그램에 대해서 한번만 더 생각하면 더 간단하게 작성할 수 있다. 조건문 (n>=10)을 생각해보면 이 조건은 변수 n이 10이상이면 1값을 가지고 10보다 작으면 0을 갖는다. 이 사실을 이용해서 다음과 같이 간단하게 줄일 수 있다.


clear all
n = input('사과의 개수는?');
cost = (1-0.2*(n>=10))*n*500;
sprintf('사과의 개수는 %d개이고 가격은 %d입니다.',n,cost)


여기서 세 번째 줄에서 사용된 조건식 (1-0.2*(n>=10))를 살펴보면 만약 변수n이 10이상이면 (n>=10)이 1값을 가지므로 (1-0.2*(n>=10))는 0.8의 값을 가지게 되고 변수n이 10보다 작으면 (n>=10)이 0값을 가지므로 (1-0.2*(n>=10))는 1.0의 값을 가지게 된다. 이 예제는 앞의 프로그램과 완전히 동일한 결과를 생성하며 if문을 사용한 예는 아니지만 조금만 생각해 보면 프로그램을 훨씬 간결하고 효율적으로 작성할 수 있음을 보여준다.

 여러 가지 조건을 한꺼번에 검사하기 위해서는 else명령어나 elseif명령어를 if문에 사용한다. if 뒤의 조건이 참(0 이외의 값)이면 뒤에 따라오는 명령문을 수행하고, 거짓(0)이면, 뒤에 나오는 나 elsief문 뒤의 조건을 판별하여 명령문을 수행한다. 문법은 다음과 같다.


if (조건1) %조건 1이 참이면 명령집합1을 수행하고 끝냄
   명령집합1
elseif (조건2) %조건2가 참이면 명령집합2를 수행
   명령집합2
else % 조건1,2 모두 거짓이면 명령집합 3을 수행
   명령집합3
end


예를 들면 다음과 같다.


if (a>1)
   k = 1;
elseif (a<-1)
   k = 100;
else
   k = 1000;
end


이 예제를 실행하고 나면 a>1 이면 k=1, a<-1 이면 k=100, -1≤a≤1 이면 k=1000 의 값을 갖게 된다. 이 예제의 경우도 다음과 같이 작성할 수 있다.


k = (a>1) + 100*(a<-1) + 1000*(a>=-1 & a<=1)


 이제 if-else-end문을 이용하여 2차 방정식의 해를 구하는 프로그램 예제를 작성해 보자. 2차 다항식 ax2+bx+c 의 세 계수를 입력받아서 판별식 D=b2-4ac를 계산한 후 이 판별식의 부호에 따라서 각각 다른 메시지를 출력하는 프로그램을 작성해보도록 하겠다. 다항식의 근을 구하기 위해 앞에서도 소개되었던 roots()함수를 이용하도록 한다. 판별식의 부호에 따라서 두 개의 실근을 가지는지, 중근을 가지는지 그리고 허근을 가지는지를 화면에 출력해보도록 하겠다.


clear all
a=input('x^2의 계수:')
b=input('x의 계수:')
c=input('상수 계수:')
D = b^2-4*a*c;
s = roots([a b c]);
if (D>0)
   sprintf('서로 다른 실근')
elseif (D==0)
   sprintf('중근')
else
   sprintf('허근')
end
s


여기에서 if-elseif-else문이 사용되었다. D가 양수냐, 음수냐, 0이냐에 따라서 다른 명령이 실행이 된다는 것을 알 수 있다.



Posted by 살레시오
,


 이전 포스트에서 MATLAB의 스크립트 파일(m파일)에 대해서 설명했는데 파일로 기록하여 수행하는 것의 장점은 다음과 같다.

       ① 동일한 작업을 손쉽게 반복하여 수행할 수 있다.

       ② 변수값 등을 변경하여 재수행하기 편하다.


스크립트 m파일을 수행할 때 명령창에서 ‘ex1'이라고 명령을 내렸었다. 즉 파일이름이 곧 명령어가 되는 것이다. 만약 현재 작업공간에 'ex1'이라는 변수가 존재한다면 명령창에는 이 변수값을 보여줄 것인가 혹은 ex1.m화일을 수행할 것인가 우선 순위의 문제가 생긴다. 명령창에 어떤 명령어가 입력되었을 경우 다음과 같은 순서에 따라 검색한다.

  1. 현재 작업공간에 그 변수가 존재 하는가 검색한다. 변수가 존재할 경우 변수값을 보여준다.

  2. 만약 변수가 존재하지 않을 경우 내부적으로 정의된 함수들(MATLAB의경우 C: \MATLAB50 \Toolbox \Internal 폴더에 존재하는 함수들)을 검색하여 동일한 함수가 있으면 그 함수를 수행한다.

  3. 현재 폴더 내의 m파일을 검색해서 동일한 이름을 갖는 m파일이 있을 경우 그것을 실행한다.

  4. 만약 현재 폴더에 그 이름을 갖는 m파일이 존재하지 않을 경우 path에 등록된 폴더들을 검색하여 그 안에 동일한 이름을 갖는 M파일이 있는지 검색하여 존재하면 그것을 실행한다.

  5. 위의 모든 경우에 해당하지 않으면 에러 메세지를 발생한다.

따라서 직접 작성하는 m파일을 저장할 때 내부함수 ( sin, cos, exp, log 등등)와 이름이 겹쳐지지 않도록 주의해야 하며 lookfor명령어(또는 help명령어)를 사용하여 지금 사용하려는 파일명이 내부함수에 있는지 확인하는 과정도 필요하다.


 스크립트 m파일을 작성할 때 유용한 입출력  명령어들을 소개하면 다음 표와 같다.


[표 1] MATLAB의 입출력 함수들

함수명

기능

sprintf()

C언어의 printf()함수와 동일한 기능을 가진 함수

disp('문자열‘)

문자열을 화면에 표시

y=input('문자열‘)

키보드로부터 입력받은 값을 y에 저장

pause

아무 키나 눌려질 때까지 대기


위의 표에서 소개한 함수중 sprintf()함수는 C언어의 printf()함수와 동일한 기능을 가진 함수이다. 이함수들을 사용하여 다음과 같은 예제를 만들어 보았다. 입력한 후 'ex2.m'화일명으로 저장하자.


n=input('Type one positive integer :');
np=prod(1:n);
disp(sprintf('%d! = %d. Press any key.', n ,np))
pause
disp('All done.')


이 예제는 입력받은 양의 정수의 팩토리얼(factorial)을 구하는 m파일이다. prod()함수는 입력벡터의 모든 요소들을 곱하여 그 값을 반환하는 함수이다. 이제 편집창에서 [f5]를 누르던가 아니면 다음과 같이 명령창에서 실행시켜 결과를 확인해 보자.


>>ex2


[그림 1] gnu octave에서 실행시킨 화면


이와 같이 input(), disp(), sprintf() 함수를 이용하면 사용자로부터 입력을 받고 화면에 결과값을 출력하는 프로그램을 작성할 수 있다.

Posted by 살레시오
,

 간단한 작업을 수행하고자 할 때에는 이전에 소개한 명령어들을 MATLAB의 명령창에서 명령을 직접 입력하여 그 결과를 확인할 수 있다. 하지만 명령어들의 수가 많아지는 경우 혹은 전에 내렸던 명령들 중에서 변수 한두 개의 값만 바꿔서 다시 수행할 필요가 있다던가 하는 경우에는 다시 일일이 명령창에서 명령들을 입력한다는 것은 매우 번거로울 것이다. 이러한 경우에는 이들 명령어들의 묶음을 파일로 저장한 후 이 파일에서 명령어들을 읽어서 그대로 수행하도록 하는 기능이 유용하다. MATLAB에서는 이러한 기능을 지원하며 이 경우 자체적으로 지원하는 텍스트 에디터 창을 이용한다. M화일이라는 것은 이렇게 작성된 파일의 확장자가 ".m"이기 때문에 붙여진 이름이다.

스크립트(script) M파일

 글로 읽는 것 보다 직접 수행하여 보면 무슨 말인지 쉽게 이해가 갈 것이다. MATLAB에서는 메뉴의 ‘파일-새 파일’을 누르거나, 툴바의 단추를 누르거나, 단축키 Ctrl+N을 누르면 명령어창 옆에 새 파일 편집창이 나타난다. 이 편집창에 다음과 같은 예제를 입력해 보라.


erasers=4;
pads=6;
tape=2;
items = erasers+pads+tape
cost = erasers*25 + pads*52 + tape*99
average_cost = cost/items


[그림 1] gnu octave 에서실행한 모습


그리고 적당한 폴더를 만든 후 이 파일명을 “ex1.m"으로 하여 저장한다. 그 후 이 파일을 실행하려면 다음과 같이 두 가지 방법이 있다.

① 편집창 메뉴에서 Debug>Run(단축키 [F5])을 선택하면 명령창에 현재 편집창에 있는 명령어들이 순차적으로 수행된다. (gnu octave에서도 동일한 방법으로 수행하 수 있다.)

② 명령창에서 파일을 저장한 폴더로 경로를 바꾼다음 (cd 명령어 이용) 명령줄에 다음과 같이 입력한다.


>>ex1


그러면 다음과 같은 결과를 보게 될 것이다.

[그림 2] gnu octave에서 예제를 실행한 모습


위의 세 줄은 명령의 끝에 세미콜론(;)이 있어서 실행 결과가 안 나타나는 것이고 뒤의 세 줄에는 세미콜론이 없으므로 그 실행결과가 명령창에 나타난 것이다. 따라서 세미콜론을 이용하여 중간 과정이나 중요치 않은 결과는 화면에 보여주니 않고 중요한 연산결과만을 화면에 나타나도록 할 수 있다. 작업공간에 여섯 개의 변수가 생성됨을 변수창에서 확인할 수도 있다. 위의 결과에서 알 수 있듯이 M파일에 기록된 명령어들이 ‘순차적으로’ 수행된다. 즉 명령창에서 다음과 같이 하나씩 명령을 내려주는 것과 완전히 동일한 작용을 한다.


>>erasers=4;
>>pads=6;
>>tape=2;
>>items = erasers+pads+tape
>>cost = erasers*25 + pads*52 + tape*99
>>average_cost = cost/items


따라서 이러한 M파일을 스크립트(script) M화일이라고 한다. 스크립트란 ‘대본’이라는 뜻이므로 배우가 대본에 쓰인 순서대로 대사를 읊어나가고 적힌 대로 연기를 하듯이 스크립트 M파일에 기록된 것을 MATLAB이 읽어서 순서대로 명령을 수행을 한다.



Posted by 살레시오
,

 MATLAB에서 여러 개의 그래프를 분할하여 하나의 그래프 창에서 모아 그리고자 하는 경우 subplot 명령을 이용한다. subplot 명령을 사용하면 그래프 창을 분할하여 다수의 그래프를 하나의 그래프 창에 도시할 수 있다. 이 명령어의 입력 인자는 그래프 창을 분할하는 행의 개수, 열의 개수 그리고 몇 번째 그래프인지를 지정하는 수의 세 개이다.


 예를 들어 subplot(2,2,3)한 후 plot(x,y)를 하면 하나의 그래프 창을 가로로 이분할, 세로로 이분할하여 3 번째의 위치에 x, y 벡터로 구성된 그래프를 도시한다는 명령이 된다. 그래프의 순서를 세는 것은 맨 첫 번째 행부터 가로로 세어 나가는 것을 원칙으로 한다.


>> x=linspace(0,2*pi,100);
>> subplot(2,2,3)
>> plot(x,sin(x))
>> subplot(2,2,2)
>> plot(x,cos(x))


[그림 1] 실행 결과 (gnu octave 실행 화면을 캡쳐한 것임)


우선 화면이 가로 세로 각 2 개씩 4 분할되는 것을 확인할 수 있으며 두 번째와 세 번째 위치에 그래프를 그리게 된다. 왼쪽 하단의 그래프가 먼저 그려지고 오른쪽 상단의 그래프가 나중에 그려지게 된다.


[그림 2] 2x2 로 분할한 경우 각 부분의 번호


각 분할 그래프의 선 모양, 색깔 바꾸기 등은 전에 설명한 바와 같이 그래프 정보 대화상자에서 할 수 있으며 명령어창에서도 가능하다. 명령어창에서 하려면 우선 subplot 함수를 이용하여 바꾸고자 하는 분할 그래프를 선택한 후 plot이나 title 등 원하는 함수를 이용하여 수정하고 나타낸다.


 다른 예를 들면 다음과 같다.


>> x=linspace(0,2*pi,100);
>> subplot(211), plot(x,sin(x))
>> subplot(212), plot(x,cos(x))


이 경우는 화면은 2분할하여 첫 번째 부분 화면에는 sin(x)를 그리는 것이고 두 번째 부분화면에는 cos(x)를 그리는 예제이다.

[그림 3] 실행 결과 (gnu octave 실행 화면을 캡쳐한 것임)


[그림 4] 2x1 로 분할하였을 경우의 그래프 번호


이 예에서와 같이 subplot()함수의 세 개의 인수는 각각 콤마(,) 로 구분하여 줄수도 있고 뿥여서 하나의 숫자로 넘겨줄 수 도 있다.



Posted by 살레시오
,