Scilab함수는 다음과 같이 세 가지 상태가 있다.


➊ 컴파일이 안 된 상태

➋ 컴파일이 된 상태

➌ 프로파일링을 위한 구문이 들어간 상태로 컴파일 된 상태


만약 콘솔에서 함수를 정의한다면 endfunction이 입력되는 순간 컴파일이 된 후 workspace에 함수가 로드된다. 따라서 그 즉시로 호출하여 사용할 수 있다. 파일로 저장된 Scilab함수는 그 자체로는  컴파일이 안된 상태이고 Scilab에서 이 함수를 사용하기 위해서는 반드시 컴파일한 후 workspace에 로드하여야 한다. 프로파일링(profiling)이란 함수를 실행하는데 각각의 줄(line)이 몇 번 실행되었는지 그리고 실행 시간이 얼마나 되는지를 분석하는 것을 말하며 이를 위해서는 추가적인 구문이 필요하다. 함수가 컴파일 된 것인지 아닌지를 확인하려면 type(functoin_name) 함수를 실행해보면 된다. 결과값이 11이면 컴파일이 안된 함수이고 13이면 컴파일된 것이다.


 Scilab에서 함수를 생성하는 방법은 콘솔창에서 직접 입력하는 방법 외에도 다음에 소개하는 deff()함수를 이용하는 방법과 파일(sci파일)에서 로드하는 방법이 이다.

인라인 함수

 함수를 생성하는 방법은 앞 장에서 설명한 바와 같이 콘솔창에서 직접 입력하는 방법 외에 deff()함수를 이용하여 인라인 함수(in-line function)을 생성하는 방법도 있다. 예를 들어서 다음과 같다.



deff() 함수의 첫 번째 인자는 함수 헤더이고 두 번째 인자는 함수의 본체인데 반드시 문자열로 입력해야 한다. 세 번째 인자는 선택 사항인데 함수를 컴파일할 것인지 (‘c’) 아닌지 (‘n’)를 지정하는 문자열이고 생략하면 ‘c’가 기본적으로 선택된다. (‘p’는 프로파일링 기능을 넣은 컴파일 옵션임) 컴파일을 하는 것이 훨씬 더 실행 효율이 높으므로 보통은 기본 옵션으로 생성하면 문제가 없을 것이다.

파일에 저장된 함수

 함수를 파일에서 정의할 수 있으며 Scilab 함수 파일의 확장자는 .sci 으로 정해져 있다.( 다른 확장자도 사용할 수는 있다.) Scilab 의 sci파일에는 여러 개의 함수가 정의될 수 있으며 파일명과 함수명은 크게 상관이 없어서 서로 달라도 된다. 그리고 외부에서 각각의 함수를 개별적으로 호출할 수 있다. (MATALB은 파일명과 첫 함수명이 같아야 하고 첫 번째 함수를 제외하고 다른 함수들은 외부에서 호출할 수는 없다.)


 파일에 저장된 함수를 사용하기 위해서 컴파일/로드 되어야 한다. 이것을 수행하는 함수는 exec()함수이며 이 함수는 스크립트파일을 실행할 때뿐만 아니라 함수를 컴파일하고 로드하는데에도 사용된다. (인라인 함수를 정의하는 deff()함수도 컴파일을 자동으로 수행한다.)


>> exec(‘filename’ [,mode])


만약 함수 파일이 현재 디렉토리에 있다면 파일명만 써도 되는데 그렇지 않다면 파일명을 포함한 전체경로를 첫 번째 인자로 써주어야 한다. 두 번째 인자는 실행모드로서 선택사항이다. 옵션으로 주는 mode값과 해당하는 동작은 다음과 같다.


[표 1] exec()함수의 mode 옵션

mode 값

동작

0

초기값. 세미콜론(;)이 붙지 않은 명령의 결과만 콘솔창에 출력.

-1

아무런 출력도 하지 않음.

1

(마치 직접 콘솔창에 입력하듯이) 한 줄씩 명령과 그 결과를 출력.

2

프롬프트(-->>) 표시 ??? (0번과 거의 유사함)

3

각 명령 줄과 프롬프트 표시. (2번과 거의 유사함)

4

???

7

한 줄씩 실행 후 멈춤. 엔터키 입력으로 실행 (데모를 보일 때 유용함)


exec()함수로 읽어들인 사용자 함수는 workspace에 컴파일되서 올라오므로 바로 사용가능하다.



Posted by 살레시오
,

 어떤 함수가 실행되면 기본 작업공간과 별도로 그 함수만의 작업공간이 생성되어 함수 내부에서 사용되거나 생성된 객체가 저장되게 된다. 그리고 함수의 실행이 끝나면 그 작업공간은 소멸되므로 함수 내에서 초기화된 변수는 함수의 실행 끝나는 시점에서 소멸된다. 함수 내부에서 사용할 수 있는 외부 변수는 다음과 같은 세 가지 경로로 전달된다.


       ❶ 입력 변수

       ❷ global로 선언된 변수

       ❸ 함수 내부에서 초기화되지 않고 호출된 곳의 workspace에서 정의된 변수


여기서 ❶과 ❷는 MATLAB에서도 동일하지만 ❸의 경우는 그렇지 않다. 함수가 호출되면 호출된 곳의 작업공간과는 별도로 그 함수만의 분리된 작업공간이 생성된다. 편의상 호출된 곳의 작업공간을 기본 작업공간(base workspace, BWS)라고 칭하겠다. 만약 함수 내부에서 어떤 변수를 참조하려고 하면 먼저 자신의 작업공간을 먼저 검색해보고 만약 없다면 기본 작업공간에서 찾아본다. 두 곳 모두에서 없다면 에러가 발생될 것이다.


예를 들어서 다음과 같은 함수가 정의되었다고 가정하자.


function y=fA(x)
         w=(w+1)^2 // (a)
         y=x*w // (b)
endfunction


이렇게 정의한 후


>> fA(1)


이라고 호출하면 에러가 발생된다. 왜냐면 (a)의 우변에서 쓰이는 변수 w는 현재의 workspace에서도 없고 기본 작업 공간에서도 초기화되지 않았기 때문이다.


[그림 1] 작업 공간의 개념도


하지만


>> w=1
>> fA(1)


와 같이 변수 w를 먼저 초기화한다면 이제는 4라는 결과값이 표시될 것이다. 한 가지 정말로 혼동하기 쉬운 것은 (a)의 우변의 변수 w는 기본 작업 공간에서 참조하고 좌변의 w는 이 함수 자신의 작업 공간에 새로운 변수로 초기화된다는 것이다. 따라서 (b)의 변수 w는 이렇게 새롭게 생성된 변수가 참조된다. 기본 작업 공간의 변수 w가 아님에 주의해야 한다. 이 변수 w와 기본 작업 공간의 변수 w는 별개의 것이므로 기본 작업 공간에서는 여전히 1값을 유지한다. 이렇게 기본 작업 공간에서 이미 초기화되어 있는 변수를 함수 내부에서 다시 초기화한 경우 “shadowed” 되었다고 하며 이 경우 기본 작업 공간의 변수를 접근할 수는 없게 된다.


[그림 2] 함수의 작업공간과 기본 작업공간은 분리되어 있다.


 만약 기본 작업 공간에서 변수 w를 global로 지정한 후 초기화했다면 어떤 일이 발생할까.


>> global w, w=1
>> fA(1)
>> disp(w)


이 경우에도 변수 w는 여전히 1값을 유지하며 global로 지정했더라도 함수 내부에서 그 값을 변경할 수는 없다. 즉, 앞의 경우와 동일하게 동작한다는 것이다. 그렇다면 함수 내부에서 여전히 기본 작업공간의 변수를 접근할 수 있는데 global로 지정해주어야 하는 필요가 있을까하는 의문이 생긴다. 일견 아무런 차이점이 없어 보이기 때문이다. 함수 내부에서 상위 workspace의 변수값을 변경해주려면 함수의 내부에서도 global로 지정해 주어야 한다.


function y=fB(x)
         global w
         w=(w+1)^2
         y=x*w
endfunction


이제


>> fB(1)
>> disp(w)


를 실행하면 변수 w는 4로 바뀐다. 즉, 상위 workspace의 변수 w가 fB()함수 내부에서 바뀐 것이다. 이와 같이 외부 변수의 값을 바꿀 필요가 있다면 외부에서뿐만 아니라 내부에서도 그 변수를 global로 지정해 주어야 한다.

[그림 3] 글로벌 변수의 동작 개념도


 함수의 결과값을 기본 작업 공간으로 내보내는 데에도 다음과 같은 세 가지 방법이 있다.


       ❶ 출력 변수로 반환하는 방법

       ❷ global로 지정된 변수를 이용하는 방법

       ❸ resume 혹은 return 명령의 인수를 이용하는 방법


❶ 은 함수의 정의부에서 선언한 출력변수를 통해서 기본 작업 공간으로 값을 내보내는 것이고 ❷는 직전 절에서 기술한 바와 같이 함수의 내부에서 global로 지정한 변수를 통해서 기초 작업 공간에서 접근할 수 있는 전역 공간에 변수값을 내보내는 방법이다.


 함수 내부에서 return 이나 resume을 만나면 그 즉시 함수가 종료되는데 보통은 단문으로 사용되어서 함수를 강제로 종료시키는 기능을 수행한다. 하지만 다음과 같은 문법도 가능하다.


[x1, x2, … xn] = return(a1, a2, … an)
[x1, x2, … xn] = resume(a1, a2, … an)

 

이러한 명령들은 함수 내부의 변수들 a1, a2, … , an 을 호출한 곳의 작업 공간에 변수 x1, x2, …, xn 으로 내보내는 기능을 수행한다. 예를 들면 다음과 같다.


function foo(a)
           a=a+1
           b=resume(a) //(*)
           c=52 // (**)
endfunction

 

이 예제에서 (**)줄은 실행되지 않고 (*)줄에서 함수는 종료된다. 또한 기본 작업공간에 변수 b를 생성시켜서 함수 내부의 a변수 값을 넘겨주게 된다. 따라서


>> foo(42)


라고 함수를 실행시키면 workspace에 변수 b가 43값으로 생성된다.


그렇지만 Scilab 매뉴얼(도움말)에 의하면 이러한 용법은 쓸데없이 프로그램의 복잡도만 증가시키므로 출력 변수를 이용하는 것이 바람직하다고 기술되어 있다. 따라서 가급적 ❶번 방법을 주로 사용하고 필요시 ❷번 방밥을 사용하도록 하는 것이 좋다. 또한, resume명령은 pause명령에 의해서 실행이 멈춘 함수를 다시 시작시키는 데에도 사용되는 명령이다.



Posted by 살레시오
,

 이전 포스트에서 plot()명령을 내리면 창이 자동으로 생성됨을 확인할 수 있다. 여기에서는 사용자가 임의로 여러 개의 그래프 창을 선택(생성)하고, 내용을 지우고, 창을 닫는 기능을 설명하도록 하겠다.


 그래프 창은 각각 고유의 아이디를 가지고 있다. 현재 열린 여러 개의 그래프 창들 중에서 특정한 아이디를 갖는 그래프 창을 선택하려면 scf() 함수를 호출하면 된다. (Set Current Figure)


>> scf(n) // n번 그래프 창 선택 (없으면 생성)
>> h = scf(n) // n번 그래프창 선택(없다면 생성) (h : 핸들)
>> scf() // (직전 아이디+1)을 가지는 새로운 그래프창 생성.
              (초기에는 0번이 생성됨)


이 함수를 사용하면 그래프 창이 선택되고 만약 지정한 아이디를 가지는 그래프창이 없다면 생성된다. 이후의 plot 명령은 이렇게 선택된 창에 그래프가 그려지게 된다. 그래프 창의 캡션바에 보면 이 아이디가 표시된 것을 확인할 수 있다.



이 아이디는 현재 그래프 창을 선택하거나 핸들(handle)을 얻거나(gcf 함수 이용) 창을 소멸시키는 등의 일을 할 수 있는 그래프 창의 고유 번호이다. 아이디로부터 핸들을 얻기 위해서는 다음과 같이 gcf()함수를 이용한다.


>> h=gcf() // 현재 선택되어 있는 그래프 창의 핸들을 얻는다.
>> h=gcf(n) // 아이디가 n인 그래프 창의 핸들을 얻는다.


아이디와 핸들은 구분해야 하는데 아이디는 여러 개의 그래프 창을 열었을 때 각각을 구분하기 위한 번호인 반면  핸들은 그래프 창의 각종 속성을 제어할 수 있는 내부 변수값으로서 자동으로 생성되어 부여된다. 여러 개의 그래프창들이 열려 있을 때 특정 아이디를 가지는 그래프창을 선택할 때도 이 함수를 사용하면 된다.


 현재 그래프 창에 그려진 내용을 지우려면 clf()를 이용하면 된다. 용례는 다음과 같다.


>> clf() // 현재 그래프의 모든 내용을 지운다.
>> clf(h) // 핸들이 h인 그래프창의 모든 내용을 지운다.
>> clf(n, ‘reset’) // 아이디가 n인 그래프 창의 모든 내용을 지우고 속성도 초기화시킨다.


두 번째 인수로 ‘clear’ 나 ‘reset’을 줄 수 있는데 ‘clear’는 단순히 내용만을 지우는 것이고 ‘reset’은 내용을 지운 후 변경된 속성까지 초기화시키는 것이다.


 그래프창을 닫으려면 close()나 xdel()함수를 이용하면 된다. 아이디로 닫으려면 xdel()함수를 이용하고 핸들로 닫으려면 close()함수를 이용하면 된다.


>> xdel() // 현재 선택된 그래프창을 닫는다.
>> xdel(n) // 아이디가 n인 그래프창을 닫는다.
>> close() // 현재 선택된 그래프창을 닫는다.
>> close(h) // 핸들이 h인 그래프창을 닫는다.



Posted by 살레시오
,

2차원 그래프

 Scilab에서 2차원 그래프를 그려주는 함수들 중 자주 사용되는 것들을 다음 도표에 정리하였다.


[표 1] Scilab의 2차원 그래프 함수

함수

기능

plot()

x-y 그래프를 그려준다.

polarplot ()

극좌표 그래프를 그려준다.

bar(), barh()

막대그래프

histplot()

히스토그램

pie()

파이차트


가장 많이 쓰이는 함수는 plot()함수이다.

plot() 함수

 plot()함수는 가장 기본적인 2차원 x-y 그래프를 만들어주는 함수로서 사용법이 MATLAB의 그것과 매우 유사하다. 첫 번째 예로 sin(x)의 그래프를 0과 2*%pi 범위에서 그려보도록 하겠다. 먼저 x벡터를 linspace()함수를 이용하여 다음과 같이 생성한다.


>> x = linspace(0, 2*%pi)


그 다음 y 데이터를 다음과 같이 생성한다.


>> y = sin(x)


그럼 다음 plot()함수를 이용하면 된다.


>> plot(x, y)


plot 함수의 내부적인 작동은 x-y 쌍의 점들을 직선으로 이어주는 것이다. 이 예에서는 100개의 (x,y) 좌표점을 서로 직선으로 연결하였으며 점들이 조밀하므로 마치 곡선처럼 보이는 것이다. 주의할 점은 x가 행벡터라면 y도 행벡터여야하고 x가 열벡터라면 y도 열벡터여야 한다는 점이다.


 다른 방법으로는 x좌표만 생성한 후 두 번째 인수로 함수명을 적어주는 것이다.


>> plot(x, sin )

 

그러면 자동으로 x벡터에 대해서 sin(x)를 구한 다음 그래프를 생성해 준다. (이 방법은 별로 권장되지 않는다.)


 만약 x는 행벡터이고 y가 행렬이라면 y행렬의 각각의 행에 대해서 그래프를 그려준다. 이 때 x의 열수와 y의 열수는 같아야 한다. 예를 들어서


>> Y = [sin(x); cos(x)]


명령은 Y 행렬을 만들어 주는데 첫 행은 sin(x)함수 값들이, 두 번째 행은 cos(x)함수 값들이 대입된다. 이제


>> plot(x, Y)


라고 하면 다음과 같이 x-Y(1,:) 과 x-Y(2, :) 에 대한 그래프를 하나의 창에 도시한다. 이 명령은 다음과 동일하다.


>> plot(x, sin(x), x, cos(x))

 

아래 결과를 보면 두 개의 그래프를 한 개의 그래프창에 도시하고 자동으로 색상이 다르게 지정되었음을 확인할 수 있다.



 함수 plot()의 세 번째 옵션으로 선의 색과 모양을 지정해 줄 수 있다. 아래 표에 자세한 옵션을 정리하였다. (MATLAB의 옵션과 매우 흡사하다.)


[표 2] plot()함수에서 선의 모양 지정자

기호

선 색

모양

기호

모양

마커

기호


r

red

-

직선(solid line)

+

Plus sign

g

green

--

파선(dashed line)

o

Circle

b

blue

:

점선(dotted line)

*

Asterisk

c

cyan

-.

일점쇄선 (dash-dotted line)

.

Point

m

magenta



x

Cross

y

yellow



's'

Square

k

black



'd'

Diamond

w

white



^

Upward-pointing triangle





v

Downward-pointing triangle





>

Right-pointing triangle





<

Left-pointing triangle





'p'

Five-pointed star (pentagram)






No marker (default)


이 세 가지 옵션을 조합하여서 다양한 선의 모양을 나타낼 수 있다.  예를 들어서 파란색 파선으로 그리고 싶다면 ‘b--’ 라고 세 번째 옵션으로 주면 된다.


>> plot(t, sin(t), ‘b--’)



실선을 유지하고 녹색원으로 마킹을 하려면 ‘g-o’라고 입력하면 된다.


>> plot(t, cos(t), ‘g-o’)



 그래프 축에 격자선(grid)을 추가하려면 xgrid(n)함수를 실행시키면 된다. n은 자연수로서 격자선의 색을 지정한다. 예를 들면 다음과 같다.


>> plot(t, cos(t), ‘r:’)
>> xgrid(2)

 


이 그림을 보면 xgrid(2) 명령에 의해서 파란색 격자선이 x축과 y축에 생겼음을 알 수 있다.


 그래프의 축의 범위를 지정하려면 mtlb_axis()라는 함수를 이용하면 된다.(Matlab의 axis라는 함수와 유사하게 만들어진 함수임) 예를 들어서 위 그래프에서 x축의 범위를 정확히 [0, 2pi] 범위로 맞추고 y축은 [-2, 2]로 넓히고 싶다면 다음과 같이하면 된다.


>> mtlb_axis([0 2*%pi -2 2])


또한 이 그림에 제목을 붙이려면 title() 함수를 이용한다.


>> title(‘sin and cos’)


그러면 그림의 상단에 그럼의 제목(title)이 생성된다. x축에 제목을 붙이는 함수는 xlable()이고 y축은 ylabel()함수를 사용한다.


>> xlabel(‘x-axis’)
>> ylabel(‘y-axis’)


타이틀과 x축, y축을 한꺼번에 지정하고 싶다면 xtitle()함수를 이용하면 된다.


>> xtitle(‘sin and cos’, ‘x-axis’, ‘y-axis’)


입력 인수는 차례대로 제목, x축 라벨, y축 라벨로 표시할 문자열이다. 만약 각각의 라벨을 사각형으로 둘러쌀려면 마지막 옵션으로 1을 주면 된다.


>> xtitle(‘sin and cos’, ‘x-axis’, ‘y-axis’, 1)

 

재미있는 것은 title(), xaxis(), yaxis, xtitle() 명령은 LaTeX 명령어를 사용할 수 있어서 미려한 수식을 출력할 수 있다. 예를 들면 다음과 같다.


>> title(‘$\frac{sin(x)}{x}$’)

 

 여러 개의 그래프를 하나의 그래프 창에 도시하려면 subplot(r,c,n)함수를 사용하면 되는데 현재 그래프 창을 r행 c열로 분할한 다음 그 중 n번을 선택한다. 예를 들면 다음과 같다


>> subplot(2,1,1) // ❶
>> plot(t,sin(t),'b:+')
>> subplot(2,1,2) // ❷
>> plot(t,cos(t),'k-.')


위의 ❶에서 subplot(2,1,1)이라고 입력했는데 이것은 현재 그래프 창을 2x1 으로 분할한 다음 그 중 1번째 자식창을 선택한다. 따라서 그 다음에 오는 plot()함수는 그 1번 자식창에 그려진다.  ❷에서는 subplot(2,1,2) 라고 했는데 2번째 자식창을 선택하는 것이다. 아래 결과를 보면 이 명령의 동작이 이해가 갈 것이다.



subplot(2,1,1) 은 subplot(211)이라고 숫자들 길 그냥 붙여서 쓸 수도 있다. 예를 들어서 subplot(221)이라면 2x2로 나누고 그 중 첫 번째 자식창을 선택하라는 것이다. 이와 같이 subplot()함수를 이용하면 하나의 그래프 창에 여러개의 그래프를 분할하여 도시할 수 있다.



Posted by 살레시오
,

 Scilab의 for 명령은 반복을 수행하기 위해서 사용되며. for 와 end 사이의 명령어들을 주어진 변수값을 가지고 반복 수행한다. 간단한 예를 들면 다음과 같다.

--> for n=1:5, disp(n), end


이 명령은 disp(n)이라는 명령을 반복해서 수행하는데 다음과 같은 결과를 표시한다.


         1.
         2.
         3.
         4.
         5.

 

이 예제에서 반복은 벡터에 대해서 수행되었다. 이전에 콜론(:) 연산자는 행벡터를 생성한다고 설명한 바 있다. 따라서 위의 예는 다음과 완전히 동일하다.

--> for n=[1 2 3 4 5], disp(n), end

하지만 전자의 경우가 훨씬 더 간략하므로 만약 등간격의 변수들에 대한 반복을 수행한다면 전자와 같이 사용하는 것이 더 일반적이다. (1부터 1000까지 반복하는 경우라면 후자같이 사용하지는 못할 것이다.)

 만약 1부터 10까지의 숫자 중 홀수에 대해서만 반복을 수행하고 싶다면 다음과 같이 하면 될 것이다.


--> for n=1:2:10, disp(n), end

 

그려면 화면에는 1부터 시작해서 하나씩 건너 뛴 숫자들을 표시할 것이다.


         1.
         3.
         5.
         7.
         9.

 

증분값을 음수로 주면 역순으로 수행할 수도 있다. 예를 들어서


--> for n=5:-1:1, disp(n), end

이라고 하면 화면에 5부터 1까지 역순으로 표시되는 것을 확인할 수 있다.

 for 반복문에서 사용되는 변수값은 꼭 정수뿐만 아니라 다양한 값이 될 수 있다. 실수의 예를 들면 다음과 같다.

--> for n=linspace(0,1,5),disp(n),end
    0.  
    0.25  
    0.5  
    0.75  
    1.  

또는 다음과 같이 실수가 아닌 경우도 된다.


--> for n=[0.1, %i, %pi, %e],disp(n),end
    0.1  
    i    
    3.1415927  
    2.7182818

 

반복 변수에 행렬이 지정될 때에는 그 행렬의 각각의 열벡터로 반복을 수행한다. 예를 들어서

--> for n=[1 2 3;4 5 6], disp(n), end

라는 반복문의 경우 세 번 반복이 수행되는데 각각의 반복문에서 n변수의 값은 [1;4], [2;5], [3;6], 즉 첫 번째 열, 두 번째 열, 그리고 세 번째 열이 된다. 따라서 결과는 다음과 같다.


   1.  
   4.  
   2.  
   5.  

   3.   
   6.  



Posted by 살레시오
,

 scilab에서 어떤 조건이 참인지 거짓인지 판별한는데 if 명령이 사용되며 만약 if 문 바로 뒤의 조건문이 참이라면 명령문들을 수행한다. if 문은 반드시 end문과 쌍을 이루어야 한다. 간단한 예를 들면 다음과 같다.


>> if %t then
     disp(“True!”)
  end


이 예는 if 문 뒤의 진리값이 항상 참이므로 then과 end 사이의 명령이 항상 실행될 것이다. else 문을 이용하면 진리값이 거짓일 경우 수행될 코드를 처리할 수 있다.


>> n=%e;
>> if n==%pi then
       a=1
   else
       a=2
   end


위의 조건 검사문은 if문 뒤의 조건이 거짓이므로 변수 a는 2값을 가질 것이다. 또한 elseif 명령을 이용하여 여러 조건 검사를 한꺼번에 수행할 수도 있다.


>> n=2;
>> if n==%pi then
     a=1
  elseif n==%e then
     a=2
  else
     a=3
  end


위의 예에서 변수 a는 3값을 가지게 될 것이다.


 조건검사에 쓰이는 비교 연산자를 다음 표에 정리하였다.


[표 1] 조건 검사에 사용되는 비교/논리연산자

비교연산자

설명

a==b

(비교연산자) 같다

a~=b 혹은 a<>b

(비교연산자) 다르다

a<b

(비교연산자) 크다

a>b

(비교연산자) 작다

a<=b

(비교연산자) 크거나 같다

a>=b

(비교연산자) 작거나 같다

a & b

(논리연산자) and

a | b

(논리연산자) or

~a

(논리연산자) not


‘같다’를 검사하는 연산자는  == 이며 = 가 아님에 주의해야 한다. 조건식에 대입연산자 =를 사용하면 에러를 발생하게 된다.


 대소비교를 하는 <, >, <=. >= 네 개의 연산자는 피연산자로 오직 실수(행렬)만이 허용됨을 유의해야 한다. 복소수는 수학적으로도 대소 관계가 정의되어 있지 않으므로 Scilab에서도 그것이 허용되지 않는다.


>>1+2*%i < 3
        !--error 144
Undefined operation for the given operands.
check or define function %s_1_s for overloading.

단 ==, ~= (혹은 <>) 연산은 허용된다. 복소수의 경우 실수부와 허수부가 모두 같아야 참(%t)이 반환될 것이다.


 논리 연산자를 사용할 때 한가지 알아두어야 할 점은 피 연산자가 벡터(행렬)인 경우이다. 다음 예들을 보자.


>> [1 2 3] == 1
ans  =
 T F F  

>>[1 2 3] == [1 2]
ans  =
 F  

>>[1 2;3 4] == [1 2; 3 5]
ans  =
 T T  
 T F  


위의 예들에서 보듯이 다음과 같이 정리할 수 있다.


       ➊ 하나가 스칼라, 다른 하나가 행렬일 경우 스칼라와 행렬의 모든 요소를 비교한다.

       ➋ 둘 다 행렬이고 크기가 다를 경우 거짓 (%f)가 반환된다.

       ➌ 둘 다 행렬이고 크기가 같을 경우 같은 위치의 요소끼리 비교한다.


만약 행렬의 상동을 if 문으로 비교할 경우 크기와 모든 요소가 같아야 참으로 간주된다.


>>a=0
>>A=[1 2; 3 4]
>>B=[1 2;3 5]
>>C=[1 2;3 4]
>> if A==B then // [T T; T F]
     a=1;
  elseif A==C then // [T T;T T]
     a=2;
  else
     a=3;
  end


위의 예에서 변수 a는 2값을 가질 것이다.



Posted by 살레시오
,

다항식 생성

 Scilab에서 다항식을 생성하는 함수는 poly() 이다. 예를 들면


>> f = poly( [1 2 3], 'x', 'c') // ‘coeff’
f  =
              2  
   1 + 2x + 3x  
>> g = poly( [1 2 3], 't', 'r') // ‘roots’
g  =
               2   3  
 - 6 + 11t - 6t + t  


위의 예에서 보듯이 poly()함수의 첫 번째 인자는 행벡터이고 두 번째 인자는 다항식 표기에 쓰이는 기호이고 세 번째 인자는 벡터의 요소가 계수(coefficients)인가 근(roots)인가를 지정하는 문자열이다. 세 번째 인자의 기본값은 ‘r’ 이므로 생략하면 이것으로 자동으로 지정된다.

다항식의 기호식(symbolic) 연산

 Scilab에서 특이한 것은 다항식으로 한 번 정의되면 그 변수는 일종의 기호식(symbolic equation)같이 취급되어 기호식 연산을 할 수 있다는 것이다. (아마 기본 연산자가 다르게 동작하도록  오버로딩 되어있는 듯하다.) 예를 들어서


>> s = poly([1 -1],'x','c') // 변수 s는 기호식으로 취급됨
s  =
   1 - x  

>> f = s^3
f  =
              2   3  
   1 - 3x + 3x - x  
>> g = 1+s+s^2
g  =
             2  
   3 - 3x + x  

>> h = g/f
h  =
               2    
     3 - 3x + x      
   ----------------------    
              2   3  
   1 - 3x + 3x - x  


위의 예에서 보듯이 s=x-1 이라는 다항식으로 s가 정의된 이후에는 사칙연산이 다항식에 대한 것으로 바뀌어서 적용이 된다. 변수 h 는 분수식으로 정의되었다.


 단순하게 x를 기호로 설정하려면 다음과 같이 하면 된다.


>> x = poly(0,’x’)


이후에는 변수 x는 다른 객체로 재설정 하지 않는다면 기호로 취급된다. 예를 들어서 분수식 x.(x2+x+1) 를 입력하고 싶다면 그대로 입력하면 된다.


>> k = x/(x^2+x+1)
k  =
        x      
   ---------  
            2  
   1 + x + x  


이렇게 정의된 k 역시 기호식으로 취급된다.


 Scilab의 내부 변수 중에 %s와 %z (소문자이다)가 있는데 이것은 이미 기호식으로 미리 정의가 되어 있는 것이다. 즉 %s=poly(0,’s’), %z=poly(0,’z’) 와 같이 미리 정의 되어 있는 기호이다. Scilab자체가 제어 이론의 구현에서 출발했으므로 전달함수를 표기하는 두 변수 s (연속치 계통의 경우) 와 z (이산치 계통의 경우)를 미리 기호식으로 사용할 수 있도록 설정해 놓은 것으로 짐작된다. 이 두 기호 이외의 다른 기호를 사용하려면 일일이 poly()함수를 사용하여 지정해 주어야 한다.

다항식과 분수식에 관련된 함수들

 다음 표에 다항식과 분수식에 관련된 중요한 함수들과 그 기능을 정리하였다.


[표 1] 다항식 관련 함수들

함수명

기능

roots

다항식의 해를 구한다.

factors

다항식을 인수분해한다.

simp

분수식에 공통분모가 있다면 약분한다.

simp_mode(%t)

simp_mode(%f)

분수식을 자동으로 약분한다.

분수식을 자동으로 약분하지 않는다.

pfss

분수식을 부분 분수 전개한다.

inv

역행렬 계산

det

행렬식 계산


예를 들어서 다항식 s3-1 을  인수분해하려면 다음과 같이 하면 된다.


>> factors(%s^3-1)
  ans  =
    ans(1)
           2  
  1 + s + s  
   ans(2)
   - 1 + s


또한 [1/z 1 1; 1 1 z; 1 z 1] 이라는 3x3행렬의 역행렬을 구하려면 다음과 같이 하면 된다.


       >>inv([1/%z 1 1; 1 1 %z; 1 %z 1])
          ans  =
                  2                      
           - z - z       z         z    
             -----     -----     -----  
           - 1 + z   - 1 + z   - 1 + z  
                              
               z       - 1       0      
             -----     -----     -      
           - 1 + z   - 1 + z     1      
                              
               z       0         - 1    
             -----     -         -----  
           - 1 + z     1       - 1 + z

부분분수 전개는 pfss 함수이다. 예를 들어서 분수식 3/(s3-1)을 부분분수전개하려면 다음과 같이 하면 된다.


         >>pfss(3/(%s^3-1))
          ans  =
                 ans(1)
              - 2 - s    
             ---------  
                      2  
             1 + s + s  
       ans(2)
                1    
             -----  
           - 1 + s   



Posted by 살레시오
,

tlist (typed list)

 tlist는 사용자에게 특수한 데이터 객체를 정의하고 연산자를 재정의할 수 있도록 하는 아주  유용한 기능을 제공한다.  tlist의 첫 번째 인수는 반드시 문자열 (혹은 문자열 벡터) 이어야 한다. 문자열 벡터인 경우 이것의 첫 요소는 정의되는 리스트의 이름이고 나머지 문자열은 뒤따라오는 객체의 이름 (필드명)이 된다. 예를 들면 다음과 같다.


>> tlA=tlist(['example', 'first', 'second'], 1.23, [1,2])
tlA  =
      tlA(1)
!example  first  second  !
      tlA(2)
    1.23  
       tlA(3)
    1.    2.  

>> type(tlA)
ans  =
   16.  

>> typeof(tlA)
ans  =
 example  


이 예에서 tlist()함수의 첫 번째 인수는 다음과 같은 문자열 행렬인데,


[ 'example', 'first', 'second' ]


첫 번째 요소 ‘example’은 이 리스트의 이름을 지정한다. 이 이름은 1024문자까지 지정할 수 있으나 연산자 오버로딩을 하기 위해서는 8자를 넘지 말아야 한다.  그 다음 ‘first’ 는 1.23을 가리키는 문자열키이고 ‘second’는 벡터 [1, 2]를 가리키는 문자열키이다. 예를 들어서 1.23이라는 값에 접근하기 위해서는 다음과 같이 하면 된다.


>> tlA(2) // 혹은
>> tlA(‘first’) // 혹은
>> tlA.first


두 번째 요소도 마찬가지로 접근해서 값을 읽거나 다른 값으로 설정할 수 있다. 만약 두 번째 요소를 문자열로 바꾸고 싶다면 다음과 같이 하면 된다.


>> tlA(2) = = “A new value” // 혹은
>> tlA.second = “A new value”


구조체의 경우와 마찬가지로 tlA.stringKey 와 같은 방식일 경우에는 stringKey는 일반적인 식별자 규칙을 따라야 한다. 하지만 tlA(‘stringKey’)와 같은 방식으로 접근하는 경우에 문자열키는 어떤 문자열이라도 상관없으며, 이 경우 문자열을 조합해서 아니면 문자열벡터의 한 요소로 네임키를 지정해 줄 수 있다는 장점을 가진다.


 똑 같은 tlist 를 다음과 같이 생성할 수도 있는데 구조체의 경우와 유사하다.


>> tlA=tlist(['example', 'first', 'second']) ;
>> tlA.first = 1.23 ;
>> tlA.second = [1 2] ;

mlist

 mlist (matrix-oriented typed list)는 전 절에서 설명한 tlist 와 유사하지만 한 가지 중요한 차이점이 있다. 그것은 필드값을 인덱스로 접근할 수 없다는 점이다.



Posted by 살레시오
,

 Scilab에서도 tuple을 사용하여 한 번에 여러 변수를 묶는 것이 가능하다. tuple 은 괄호 (...) 를 사용하는데 각각의 요소는 반드시 comma (,)로 구분해야 한다. 이 기능을 사용하면 변수들을 서로 swap하는 데도 간결하게 사용할 수 있다.


 아래에서 첫 번째 예가 변수 a와 b 를 동시에 생성하는 것이다. 좌변에는 행렬을 생성할 때 사용하는 대괄호 [ ... ] 를, 우변에서 tuple을 지정할 때는 ( ... ) 를 사용했음에 유의해야 한다, 두 번째 예는 이 두 변수의 값을 서로 맞바꾸는 것이다.


[그림 1] Scilab에서 tuple의 사용 예


 이 tuple 은 독립적인 자료구조가 아니므로 이것 자체를 변수에 저장한다든가 하는 것은 불가능하며 변수를 지정할 때에만 사용된다. 또한 tuple안의 요소 개수와 좌변의 [...] 안에 있는 변수의 개수는 반드시 같아야 한다.





Posted by 살레시오
,

구조체는 개별적인 데이터를 하나로 묶는 자료형이며 Scilab에서도 이것을 지원한다. 예를 들어서 어떤 사람의 이름, 나이, 시력을 각각 name, age, sight 라는 이름으로 저장하고 싶다면 다음과 같이 struct()함수를 사용한다.


[그림 1] 구조체의 생성


구조체의 각각의 데이터를 필드(field)라고 칭한다. 이 예에서 person1 구조체의 필드는 name, age, sight 이다. 함수 struct() 은 반드시 짝수 개(0도 가능함)의 입력 인수를 가져야 하고 홀수 번째의 인수는 구조체의 필드 이름으로서 반드시 문자열이어야 한다. 짝수 번째 입력 인수는 진전에 입력된 필드명을 가지는 값으로서 Scilab 객체(행렬, 문자열, 등등)가 온다.


 위와 같은 구조체를 정의하는데 있어서 또 다른 방법은 개별적인 요소를 하나하나 직접 생성/입력하는 방법이 있다. 두 가지 문법이 있는데 다음과 같다.


structName(‘fieldName’)
structName.fieldName

    

두 가지 방법에는 큰 차이점이 있다. 전자의 경우는 필드명에 임의의 문자열을 사용할 수 있으나 후자의 경우는 일반적인 식별자 규칙을 따라야 한다는 것이다.


[그림 2] 구조체의 생성 (다른 방법)


구조체의 필드를 접근한다던가 아니면 추가하는데 있어서도 위에서 설명한 바와 같이 두 가지 방법이 있다. 예를 들어서 age필드를 접근하려면


a = person1.age // 읽기
person1.age = 43 // 변경
a = person1(‘age’) // 읽기
person1(‘age’) = 43 // 변경


새로운 필드도 자유롭게 추가할 수 있다.


person1.height = 170  // height라는 새로운 필드 추가
person1(‘height’)=170 //위와 동일함


 만약 두 개 이상의 구조체가 서로 같은 필드 이름들을 가지고 있다면 이것들을 하나의 행렬로 묶을 수 도 있다.


[그림 3] 구조체를 요소로 가지는 행렬


이 예제에서 구조체 sA와 sB는 똑같은 필드명을 가지고 있으므로 하나의 행렬로 묶을 수 있다. 필드의 값은 데이터형이 서로 달라도 상관없으며 중요한 것은 필드명이다. 필드명이 다른 두 구조체를 하나의 행렬로 묶으려고 한다면 에러를 발생한다.


 한 가지 알아야 할 것은 한 구조체에서 다른 구조체로 대입을 할 때 Scilab에서는 구조체의 내용물이 복사되는 것이지 참조가 되는 것은 아니라는 것이다. 위의 예에서


sC = sA


라고 하면 sC 변수에는 sA의 모든 구조체 필드들이 “복사된” 새로운 구조체가 생성되는 것이다. 따라서 이후에


sA.c = [1 0]


이라고 sA에 새로운 필드를 추가한다고 해서 sC에 영향을 미치지는 않는다. 이것은 구조체를 함수에 넘길 때도 마찬가지로 적용되는데 함수 내부에서 넘겨받은 구조체를 변형시킨다고 해도 원래의 구조체와는 아무런 상관이 없다는 것을 알아두어야 한다.


 구조체와 관련된 함수들은 다음과 같다.


[표 1] 구조체와 관련된 함수들

함수명

기능

struct(...)

구조체 생성

isstruct(s)

s가 구조체인지 테스트

isfield(s,f)

f가 s의 필드인지 테스트

length(s)

사용자 필드 수 + 2

fieldnames(s)

getfield(n, s)

구조체 s의 필드명을 문자열 행렬로 반환

구조체 s의 n번째 필드값을 반환

setfield

(사용 빈도가 매우 낮을 것 같음)

s = null()

구조체 s 삭제


여기서 getfiled() 함수는 구조체의 필드명을 문자열벡터로 반환하는데 3번째 요소부터 사용자 필드라는 것에 유의해야 한다. 아래 예를 보자.


[그림 4] getfiled()함수의 반환 객체


이 예에서 getfield()함수의 첫 번째 인자는 s1의 자료형이 구조체임을  나타내는 문자열이고 (내부적으로 구조체는 mlist 임.) 두 번째 인자인 dim은 Scilab에서 자동으로 생성하는 필드이다. 따라서 사용자 필드는 세 번째부터 마지막까지이다. 사용자 필드명만 뽑아내려면 다음과 같이 하면 될 것이다.


>> fields = getfield(1, s1)
>> fields = fields(3:$)


또는 간단하게 fieldnames()함수를 사용하면 된다.


>> fields = fieldnames(s1)


만약 사용자의 첫 번째 필드인 s1.A 의 값을 읽어내려면 다음과 같이 하면된다.

    

[그림 5] getfield()함수


이 내용은 혼동하기 쉬운데 이렇게 이해하면 될 것 같다. getfield(n, s) 함수는 구조체 s의 내부적인 필드”값”를 반환하는데 내부적으로 s구조체의 첫 번째 필드는 모든 필드명의 문자열벡터, 두 번째 필드는 dims, 세 번째 필드부터가 사용자 필드이다. 따라서 해당되는 것을 반환하는 것이다. 만약 위에서 예를 든 s1의 경우에는 다음 표와 같이 내부적인 데이터를 가진다.


[표 2] getfiled() 함수 반환 객체의 내부 인덱스

내부 인덱스

필드명

필드값

(getfield 함수의 반환값)

1


[ ‘st’ , ‘dims’, ‘A’, ‘b’ ]

2

‘dims’

[1 1]

3

‘A’

[1 2; 3 4]

4

‘b’

[0 1]


따라서 getfield(3, s1) 이라고 하면 s1구조체의 3번째 필드의 필드값이 반환된다고 이해하면 된다.


 하지만 구조체의 필드를 접근하는 데에는 getfield()함수나 setfield()함수를 이용하는 것 보다는 dot(.) 연산자나 문자열키로 읽거나 쓰는 방식이 더 일반적이다.


Posted by 살레시오
,