레이블이 조건문인 게시물을 표시합니다. 모든 게시물 표시
레이블이 조건문인 게시물을 표시합니다. 모든 게시물 표시

2015년 7월 29일 수요일

맥시마(maxima)의 if 조건문

 맥시마에서 조건 검사를 하는데 if 명령어가 사용된다. 문법은 다음과 같다.

if <조건식> then <expr1> else <expr2>

만약 조건식이 참이면 <expr1>이 실행되고 거짓이면 <expr2>가 실행된다. 조건식을 구성하는데 사용되는 조건 연산자는 다음과 같다.

[표 1] 조건식에 사용되는 연산자들
연산자
의미
비고
a = b, equal(a,b)
같다
관계 연산자
a # b, notequal(a,b)
다르다(≠)
a < b
크다
a > b
작다
a <= b
크거나 같다
a >= b
작거나 같다
and
and
논리 연산자
or
or
not
not

예를 들면 다음과 같다.
변수 a에 %pi 값이 들어있으니 조건은 거짓이 되므로 b:0 이 실행된다. 위의 예제는 다음과 같이 조금 더 간단하게 바꿀 수 있다.

위에서 (if a<%e else 0)가 단일 표현식이며 그 값은 조건에 따라서 1이거나 0이 된다. 따라서 조건에 따라 그 값을 변수 b에 저장시키는 것이다. and연산자를 이용한 예를 들어보면 다음과 같다.

또한 elseif 명령을 이용하여 if문을 중첩하여 쓸 수 있다.

if <조건식1> then <expr1>
elseif <조건식2> then <expr2>
elseif <조건식3> then <expr3>
...
else <exprN>

이 문법에서 만약 <조건식1> 이 참이라면 <expr1>을 수행하고 빠져나간다. <조건식1>이 거짓이고 <조건식2>가 참이라면 <expr2>를 수행한다. <exprN>은 모든 조건이 거짓일 때 수행된다. 다음 예를 보자.
이 예제에서 변수 b에는 2가 대입된다.


2015년 7월 14일 화요일

MATLAB의 반복문 while ~ end

 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문을 빠져 나오게 된다.


MATLAB의 반복문 for ~ end

 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의 행렬을 다루는 함수나 내부 함수를 이용하여 보다 효율적으로 작성하는 것을 항상 생각해 볼 필요가 있다.


2015년 7월 13일 월요일

MATLAB의 조건문 switch ~ case ~ end

 조건문을 처리하는 두 번째 방법은 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 밖으로 이동한다.