지금까지는 명령창에 명령어들을 직접 한두 개씩 입력해서 결과를 확인하는 식으로 사용하였는데 많은 경우에 명령어들을 묶어서 파일로 저장하여 한꺼번에 실행시키는 방법을 사용한다. 명령창에 명령을 직접 입력하면 Scilab 종료시 그것들이 사라지지만 파일에 저장하여 놓으면 이후에 언제라도 불러서 사용할 수 있다.

 이러한 명령어들의 집합(프로그램)을 편집하고 저장하는데 사용하는 도구가 SciNote 이다. 메뉴에서 Applications > SciNotes 항목을 실행시키면 SciNote가 실행된다. 이제 다음과 같이 간단한 프로그램을 작성한 후 적당한 폴더에 저장시키자. 필자는 test02.sce 라는 화일명으로 저장시켰다.(캡션바에 전체 경로가 표시된다.)

[그림 1] SciNote


프로그램은 3x3 난수 행렬 두 개를 생성시킨 후 그 결과를 disp()함수로 화면에 표시하도록 하는 간단한 것이다. 첫 두 줄의 끝은 세미콜론(;)을 넣어놓았다.


 이제 이것을 실행시키기 위해서 Execute 메뉴를 보면 다음 그림과 같이 여러가지 옵션이 있다.


[그림 2] sce파일 실행 옵션

그 중  ..file with echo (ctrl-L) 을 선택하거나 단축키를 누르면 다음과 같이 명령창에 표시된다. 이것은 명령창에 한 줄씩 수동으로 입력하는 것과 완전히 동일하게 작동하며 각 프로그램의 줄이 화면에 표시된다. 또한 세미콜론(;)으로 끝나면 그 결과를 표시하지 않고 그렇지 않으면 표시한다.

[그림 3] [ctrl]+[L] 단축키로 스크립트 파일을 실행한 결과

이에 반해서 Save and execute (단축키 F5) 를 실행하면 먼저 저장하고 실행한다. 이것은 명령이 화면에 표시되지도 않으며 세미콜론(;)의 유무와 상관없이 그 결과도 화면에 표시되지 않는다. 다만 이 예제의 경우 disp()함수가 사용되었으므로 이 함수의 실행결과만이 화면에 표시된다.

[그림 4] [F5] 단축키로 실행한 결과


이때 사용되는 명령어가 exec()함수이다. 이 함수는 sce파일(그리고 나중에 나올 sci파일)을 실행시키는 기능을 수행하며 다양한 실행 옵션을 줄 수 있다. SciNote에서는 -1옵션이 지정되었음을 알 수 있다. 이것에 대해서는 다른 포스트에서 더 자세히 설명하도록하고 일단 여기에서는 SciNote에서 실행시키는데 [Ctrl]+[L] 단축키나 [F5] 단축키가 사용된다는 것을 알아두도록 하자.

특수한 기능들

 명령창과 SciNote가 분리되어 있다면 프로그램 작업 시에 몇 가지 번거로운 점들이 있다. 매번 창들 사이를 클릭해서 왔다 갔다 해야된다던가, 아니면 실행 결과나 프로그램이 다른 창에 가려서 보이지 않는다던가 하는 점들이다. 이러한 불편함을 해소하기 위해서 SciNote와 콘솔창을 하나로 결합할 수 있는 기능이 있다.

[그림 5] SciNote의 위치 조절

위 그림에 표시된 막대 부분을 마우스로 드래그 하여 콘솔창에 놓으면 해당 위치에 결합이 된다. 그래프 창도 마찬가지로 도킹시킬 수 있으며 반대로 SciNote 창에 콘솔창을 도킹시킬 수도 있으므로 자유롭게 작업 환경을 설정할 수 있다.



Posted by 살레시오
,

 Scilab명령어를 담은 문자열을 실행시킬 수 있는 명령어들이 있다. 세 개가 있는데 다음 표에 정리하였다.


[표 1] 문자열을 실행시키는 함수들

함수명

기능

execstr

Scilab 명령 문자열을 실행한다.

eval

evstr

Scilab expression 실행(행렬 반환)

위와 기능은 동일하나 에러를 traping할 수 있음

 먼저 execstr()은 Scilab 명령을 담은 문자열을 실행하는 것이다. (MATLAB의 eval 함수의 기능에 해당됨.)

>> execstr('a=1+sin(%pi/2)')
>> a
a  =
    2.  

이 예에서 보듯이 execstr()함수는 세미콜론이 붙지 않은 명령이라도 그 결과를 콘솔창에 표시하지 않는다. 만약 문자열에 명령 에러가 있다면 execstr()함수는 실행이 멈추게 된다. 다음 예를 보자.

>> execstr('a=2#4'), c=%i
 a=2#4
     !--error 276
Missing operator, comma, or semicolon.
in  execstr instruction    called by :  
execstr('a=2#4'), c=%i

이 예에서 ‘a=2#4’라는 명령은 문법 오류가 있으므로 거기서 실행이 멈춰버리고 에러메서지를 밷는다. 따라서 c=%i 라는 그 뒤의 명령은 실행되지 않는다.


만약 실행을 멈추지 않고 에러의 발생 여부를 처리하고 싶다면 다음 예와 같이 옵션을 사용하면 된다.


>> ier = execstr(['a#2','b=%pi'], 'errcatch','n'), c=%i
ier  =
   4.  
c  =
   i    

   

두 번째 인수로 ‘errcatch’ 를 주었는데 이것은 에러가 발생하면 실행을 멈추지 말고 단순히  ier에 그 결과를 반환하라는 것이다. 세 번째 인수가 ‘n’ 이라면 에러의 개수를 ‘m’ 이라면 에러메세지를 반환하다. 이 경우는 execstr()함수 뒤의 c=%i 가 실행된다는 점이 앞으 경우와 다르다. execstr()함수에는 두개의 명령 ‘a#2’ 와 ‘b=%pi’ 가 들어갔는데 두 번째 명령은 오류가 없음에도 첫 번째 명령에 에러가 있으면 두 번째 것이 실행되지 않고 에러를 캐치하고 넘어가 버린다. 따라서 변수 b도 생성되지 않고 c만 생성이 된 것이다.

 함수 eval()과 evstr()은 문자열 행렬의 값을 구해서 행렬로 반환해 주는 함수이다. 두 함수의 차이점은 에러를 캐치할 수 있느냐(evstr 함수), 없으냐(eval)이다. 예를 들면 다음과 같다.

>> a=%i; b=%e;
>> A=eval(['a' 'b'; 'a+b' 'a-b'])
A  =
   i                  2.7182818        
   2.7182818 + i    - 2.7182818 + i  


 evstr()함수는 두 번째 출력 인수를 지정해 주면 그것에 에러의 번호를 반환하고 함수 자체는 실행이 멈추지 않고 정상적으로 종료된다.


>> A=eval(['a' 'c'; 'a+b' 'a-b']); d=10;
!--error 4
Undefined variable: c
at line       3 of function %eval called by :  
at line      20 of function eval called by :  
A=eval(['a' 'c'; 'a+b' 'a-b']); d=10;

 

이 예에서 eval()함수 내부의 c변수는 없는 변수이므로 에러를 발행하고 실행이 거기서 멈춰버린다. 따라서 뒤에 있는 d=10; 이라는 명령은 실행되지 않는다. 반면에 다음 예를 보자.

>> [A,ier]=evstr(['a' 'c'; 'a+b' 'a-b']); d=10;
>>d
d  =
   10.

이 예에서 evstr()은 eval()과 같은 일을 수행하지만 만약 에러가 발행한다면 두 번째 출력인수 ier에 에러의 코드를 반환하고 정상적으로 종료한다. 따라서 그 뒤에 오는 명령인 d=10;도 정상적으로 수행된다.



Posted by 살레시오
,

 함수  part() 는 문자열의 일부분을 추출하는 기능을 수행한다.

       ❶ part(str, n) // 문자열 str의 n번째 문자 추출

       ❷ part(str, n1:n2) // 문자열 str의 n1번째 부터 n2번째 까지 추출

       ➌ part(str,[n1, n2, n3…]) // 문자열 str의 n1, n2, n3… 번째 문자들을 추출하여 단일 문자열로 반환

예를 들면 다음과 같다.


>> str = "This is a sample string."
str  =
This is a sample string.  

>> strp1 = part(str, 4)
strp1  =
 s  

>> strp1 = part(str, 6:9)
strp1  =
 is a  

>> strp1 = part(str, [11 13 15 19])
strp1  =
 smlt  

만약 입력문자의 크기가 넘어가는 문자열의 범위를 지정하면 공백 문자로 채워진다. 이 예제에서 str의 길이는 24이다. 다음 예는 24를 넘어가는 인덱스에 대해서는 공백문자로 채워짐을 보이고 있다.

>> '|'+part(str,20:30)+'|'
ans  =
|ring.      |

 함수 grep(vstr1, str2)은 문자열 벡터 vstr1 의 요소(문자열) 중에서 str2가 포함된 것의 인덱스를 반환한다. 예를 들어서 다음과 같이 문자열 벡터가 정의되었다고 하자.


>> str1 = ['abcdefghijk', 'xyz', 'jklm']

이후에 grep()함수를 사용했을 때의 결과는 다음과 같다.


>> grep(str1, 'jk')
ans  =
   1.    3.  

 

즉, str1의 첫 번째와 세 번째 요소(문자열)에 ‘jk’라는 문자열이 포함되었다는 것이다. 검색할 문자열이 두 개 이상이라면 이것들을 요소로 하는 문자열 벡터를 두 번째 인수로 넣어주면 된다.

>> grep(str1, ['jk','y'])
ans  =
     1.    2.    3.  


이 예에서는 str1 문자열 벡터의 요소 중에서 ‘jk’ 나 ‘y’ 를 포함하는 것의 인덱스를 구한다.

 함수 strindex(str1, vstr2)는 문자열 str1에서 vstr2 가 시작되는 지점의 인덱스를 구해준다.


>> str1 = '[12.34;56.789;10.123]'
str1  =
 [12.34;56.789;10.123]  

>> strindex(str1, ';')
ans  =
    7.    14.  

>> strindex(str1, [';', '.', ']'])
ans  =
    4.    7.    10.    14.    17.    21.  

 

이 함수 strindex()의 첫 번째는 반드시 단일 문자열이어야 하며 결과 값은 이 문자열의 첫 문자를 1로 보았을 때의 인덱스 값이다. 위의 예들 중 마지막 예에서는 str1 문자열에서 앞에서부터 ‘;’ 또는 ‘.’ 또는  ‘]’ 인 것의 인덱스를 차례로 찾아서 반환해 준다.

 함수 sci2exp()는 입력을 Scilab 명령의 문자열로 변환시켜 준다.

>> A=[1 2;%i, %pi]
A  =
   1.     2.        
   i      3.1415927  

>> str3 = sci2exp(A)
str3  =
 [ 1, 2;%i, 3.1415927]  

>> typeof(str3)
ans  =
 string  



Posted by 살레시오
,

  Scilab에서 문자열은 큰따옴표 “ “ 로 묶거나 작은 따옴표 ‘ ‘ 로 묶을 수 있으며 숫자와 마찬가지로 변수에 대입할 수 있다. 큰 따옴표로 묶었다면 반드시 큰 따옴표로 끝나야 하며 작은 따옴표로 시작했다면 작은 따옴표로 마쳐야 한다.

>> x = ”Hello ” ; // 큰 따옴표 사용
>> y = ’world.’ ; // 작은 따옴표 사용

다른 프로그래밍 언어(예를 들어 C/C++/JVAV 등)의 경우에는 작은 따옴표가 하나의 문자를 표시하는데 이것과 혼동하지 말아야 한다. Scilab에는 하나의 문자를 저정하는  char형이라는 데이터형 자체가 없으며 작은 따옴표도 큰 따옴표와 똑같이 문자열을 만들 때 사용된다.

 두 문자열을 하나로 묶을 때에서는 덧셈(+) 기호를 사용할 수 있으므로 매우 직관적이고 편하게 사용할 수 있다.

>> z = x + y
ans=
   Hello world.

드물긴 하지만  만약 문자열 자체에 큰따옴표나 작은 따옴표가 포함되어 있다면 두 개를 연달아 써주면 된다. 예를 들면 다음과 같다.


>> s1 = 'He said ""Hello"".'
s1  =
     He said "Hello".
>> s2 = "She thinked ''It''s him!''"
s2  =
     She thinked 'It's him!'

 

위의 예는 문자열 자체에 큰 따옴표나 작은 따옴표가 포함된 경우이다.

 한 가지 더 언급할 것은 Scilab에서 문자열은 ‘문자의 배열’이 아니라 숫자와 마찬가지로 단일 데이터형으로 이해하는 것이 좋다. 뒤에 언급하겠지만 숫자가 1x1 행렬인 것처럼 단일 문자열도 1x1 크기의 행렬(더 정확히 표현하면 cell 이지만 편의상 행렬로 지칭하기로 하겠다.)로 취급된다.

기본적인 문자열 관련 함수

 함수 length()는 문자열의 길이를 반환해 준다.

>> length(s1)
ans  =
     16.

 

문자열은 숫자처럼 벡터나 행렬의 요소가 될 수도 있다. 이 경우 size()함수는 문자열 배열의 크기를  반환한다.



이 예에서 변수 sm은 2x3크기의 행렬인데 각각의 요소는 문자열로 채워져 있다. 문자열의 행렬이 length()함수의 입력이 되면 같은 크기의 행렬에  각각의 요소의 문자열의 크기를 반환한다. 어떤 행렬의 한 요소가 문자열이라면 다른 모든 요소도 문자열이어야 한다.

 문자열 합성 연산자 +는 단일 문자열뿐만 아니라 문자열 행렬에 대해서도 유사하게 사용된다.

>> cost = string([10 20; 100 110])
cost  =
        !10   20   !
        !100  110  !

>> scost = '$'+cost+'.00'
scost  =
        !$10.00   $20.00   !
        !$100.00  $110.00  !


이 예에서 string()함수는 숫자 행렬을 문자열 행렬로 바꿔주는 함수이다. 주의할 점은 + 연산자의 두 피연산자가 모두 문자열 행렬일 때에는 크기가 같아야 한다는 점이다. 두 피연산자 중 하나가 단일 문자열일 때는 그것이 다른 행렬의 모든 요소에 더해지게 된다. (이 점은 덧셈 연산자의 기본적인 성질에 부합된다. 스칼라과 행렬의 덧셈을 생각해 보라.)

함수 emptystr(r,c)은 rxc 크기의 빈문자열 행렬을 생성해준다.



이 함수를 이용하면 같은 문자열을 모든 요소로 가지는 문자열 행렬을 쉽게 생성할 수 있다. 예를 들어서 모든 요소가 ‘hello’라는 문자열인 5x3크기의 행렬을 생성하려면 다음과 같이 하면 된다.


>> samestr = emptystr(5,3)+'hello'
samestr  =
       !hello  hello  hello  !
       !hello  hello  hello  !
       !hello  hello  hello  !
       !hello  hello  hello  !
       !hello  hello  hello  !

  문자열의 각각의 문자를 아스키(ASCII) 값의 벡터로 바꿔주는 ascii()라는 함수가 있다.


>> ascii('01ABab')
ans  =
     48.    49.    65.    66.    97.    98.

 

이 예에서 문자 ‘0’의 아스키값은 48, 대문자 ‘A’는 65 임을 알 수 있다.

 이전 포스트에서 문자열들을 하나의 문자열로 합치는데 +연산자를 사용한다고 했는데 strcat()함수도 유사한 기능을 수행한다. 기본적으로 문자열의 벡터(행벡터 혹은 열벡터 상관없음) SM에대해서 함수 strcat(SM)은 모든 요소를 하나의 문자열로 합쳐준다. 기본적으로 첫 번째 요소는 문자열 벡터이다.

만약 문자열 사이에 어떤 문자열을 추가시키고 싶다면 두 번째 인자로 그 문자열을 주면 된다. 아래 예는 문자열 사이에 공백문자 ‘ ‘와 ‘+’를 추가시킨 것이다.




Posted by 살레시오
,

 프로그램을 작성하다 보면 빈행렬(empty matrix)을 생성할 필요가 가끔씩 생긴다. 즉, 요소가  없는 0x0크기의 빈행렬를 생성하려면 다음과 같이 하면 된다.


>> A = []

 

만약 행렬 A가 이전에 어떤 요소들을 가지고 있었다면 빈행렬을 대입하는 순간 그것들은 지워지고  그 요소를 저장하기 위해 할당되었던 메모리는 반환된다.

특수한 행렬을 생성하는 기본적인 함수들은 다음 표와 같다.


[표 1] 특수 행렬을 생성하는 함수들

eye(), eye(r, c), eye(M)

주대각 요소가 1인 행렬을 생성한다.

zeros(), zeros(r, c), zeros(M)

모든 요소가 0인 행렬 생성

ones(), ones(r, c), ones(M)

모든 요소가 1인 행렬 생성

linspace(c1, c2 [, n])

c1부터 c2까지 n개의 등간격 행벡터 생성. (n이 생략되면 기본적으로 100임) c1, c2 : 복소수 가능

testmatrix(‘magi’, n)

testmatrix(‘frk’, n)

testmatrix(‘hilb’, n)

nxn 매직행렬 생성

nxn Franck행렬 생성

nxn Hilbert행렬의 역행렬 생성

rand(“seed”), rand(“seed”, s)

rand(r, c [ , strKey] )

rand(M [ , strKey] )

seed값을 얻거나 설정한다. (초기에 s=0임)

r x c 크기 혹은 M행렬과 같은 크기의 난수 행렬 생성

strKey : “uniform”, “normal”, “info”

grand

더 다양한 옵션으로 난수행렬 생성

eye(M)은 M행렬과 같은 차수이고 주대각 요소가 1인 행렬을 생성하며 행렬M이 꼭 정방행렬일 필요는 없다. 주의할 점은 eye(10)이라고 입력하면 10x10 행렬이 생성되는 것이 아니라 1x1행렬이 생성된다는 것이다. (10이라는 숫자가 1x1행렬이기 때문) 그리고 덧셈과 뺄셈에서 사용될 때는 더해지는 행렬과 자동으로 같은 차수의 행렬을 생성한다. ones()와 zeros()도 같은 특성을 가진다.

 linspace(c1, c2 [,n])함수는 c1부터 c2까지 등간격으로 n개의 요소를 가지를 행벡터를 생성하는 자주 사용되는 함수이다. 예를 들어서 0부터 2π 까지 100개의 요소를 가지는 행벡터를 생성헤서 vX변수에 대입하려면 다음과 같이 하면 된다.

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

1000개로 개수를 늘리려면 다음과 같이 한다.


>> vX =  linspace(0, 2*%pi, 1000)

 

 한 가지 특이한 것은 c1, c2는 복소수도 가능하다는 것이다. 예를 들어서 c1=1+%i, c2=2+3*%i, n=5라면 간격을 나눌 때 실부부는 실수부끼리, 허수부는 허수부끼리 나눈다. 즉 다음 두 명령은 같은 것이다.

>> linspace(1+%i, 2+3*%i, 5)
>> linspace(1, 2, 5) + linspace(1, 3, 5)*%i


후자 보다는 전자가 더 간단하므로 이것을 사용하면 된다

.

 함수 rand()는 난수행렬을 생성시킨다. 이때 균일분포/정규분포를 strKey로 지정할 수 있다.


위 예제에서 histplot()은 히스토그램을 그리는 함수이다.



Posted by 살레시오
,

(A) 덧셈과 뺄셈

 두 행렬의 덧셈/뺄셈은 크기(행수와 열수)가 같아야 수행되며 다르면 에러가 발생한다. 한 가지 주의할 것은 <스칼라±행렬> 의 연산인데 수학적으로는 정의되지 않지만 Scilab 에서는  (Matlab 와 마찬가지로) 스칼라를 모든 요소와 각각 더하는 연산을 한다는 것이다.

>> A=[1 2;3 4]; B=[5*%i %pi;%e %e^2]; C=[1 2 3]; d=-2;
>> A+B
ans  =
   1. + 5.i     5.1415927  
   5.7182818    11.389056  
>> B-C
    !--error 9
 Inconsistent subtraction.
>> C+d
ans  =
 - 1.    0.    1.

위 의 예에서 보듯이 행렬 A와 B는 크기가 둘 다 2x2로 같으므로 덧셈/뺄셈이 가능하지만 B와 C는 크기가 다르다. 따라서 B와 C의 덧셈/뺄셈은 허용되지 않는다. 다만 d는 스칼라이므로 이것과 행렬과의 연산은 가능하며 모든 요소에 이 스칼라를 더하거나 빼는 연산을 수행한다.

(B) 곱셈

 행렬의 곱셈에 사용되는  연산자들은 다음 표와 같다.

[표 1]  행렬의 곱셈

A*B

일반적인 곱셈. A의 행과 B의 열의 개수는 같아야 함.

A.*B

요소간 곱셈. A와 B는 같은 크기여야 함.

A.*.B

Kronecker 곱셈.

A^n, A**n

A행렬의 n승. 즉, A*A*A*...*A. A는 정방행렬이어야 함.

A.^B

요소간 거듭제곱. A와 B는 같은 크기여야 함.

단순한 A*B 연산은 행렬의 곱셈으로서 피연산자의 한 쪽이 스칼라 이거나 아니면 A의 행 수와 B의 열의 개수는 같아야 계산이 성립한다.

>> A=[1,2+3*%i;%pi %e^2]
A  =
   1.           2. + 3.i  
   3.1415927    7.3890561

>> %i*A
ans  =
    i           - 3. + 2.i    
  3.1415927i    7.3890561i  

>> A*[1 2 3;4 5 6]
ans  =
   9. + 12.i    12. + 15.i    15. + 18.i  
   32.697817    43.228466     53.759115

>> [1 2 3]*A
         !--error 10
Inconsistent multiplication.

위의 예들에서 마지막 것은 행렬의 차수가 맞지 않아서 에러가 발생하는 것이다.


 이에 반해서 A.*B 연산은 행렬의 같은 위치에 있는 요소끼리 곱하는 연산으로서 A행렬과 B행렬의 크기가 같아야 한다.


>> P=[1 2 ; 3 4]
P  =
    1.    2.  
    3.    4.  

>> Q= [%i %pi; %e %T]
Q  =
    i            3.1415927  
    2.7182818    1.        

>> P.*Q
ans  =
    i            6.2831853  
    8.1548455    4.        

이 연산의 결과도 같은 크기의 행렬이다. 만약 크기가 서로 다른 행렬에 대해서 이 연산을 수행하려고 한다면 에러를 발생할 것이다.


>> [1 2].*[3;4]
         !--error 9999
inconsistent element-wise operation

 

그리고 A.*.B 연산은 Kronecker 곱셈으로서 수학기호로는 ⊗로 표시 한다. 즉 A⊗B는 다음과 같은 연산을 수행한다.



따라서 행렬 A와 B에 대한 크기 제약 조건은 없으며 예를 들면 다음과 같다.


>> [1 2].*.[10 20;30 40]
ans  =
   10.    20.    20.    40.  
   30.    40.    60.    80.

 

 행렬의 거듭제곱에는 ^, **, .^ 연산자가 있다. A^n, 또는 A**n 은 행렬의 거듭제곱 연산자로서 예를 들어서 A^3 또는 A**3은 A*A*A 와 결과가 같다. 따라서 이 연산이 수행되려면 A행렬은 반드시 정방행렬이어야 한다. 이에 반해서 A.^n 은 행렬의 각각의 요소를 n승 하는 것이다. 따라서 A행렬의 크기에 대한 제한 조건은 없다.

>> A=[2,3;4,5];
>> A^3
ans  =
    116.    153.  
    204.    269.  
>>A.^3
ans  =
    8.     27.  
   64.    125.  

행렬의 거듭 제곱과 요소간 거듭 제곱은 반드시 구분해야 한다. 한 가지 특이한 (혼동하기 쉬운)점은 만약 A가 벡터라면 A^n 이나 A.^n 이나 결과가 같다는 것이다. (개인적인 생각으로는 A가 벡터일 때 A^n 연산은 에러를 뱉는 것이 더 일관성이 있는 것 아닌가 하는 아쉬움은 있는데 어쨌든 Scilab은 그렇게 동작한다.(

(C) 나눗셈

 행렬의 나눗셈에 대해서 다음 표에 정리하였다. 나눗셈은 보통의 나눗셈과 좌나눗셈으로 나뉜다는 점이 특이하다.

[표 2]  행렬의 나눗셈

A/B

행렬의 나눗셈. A*inv(B)와 같다.

한 쪽이 스칼라이거나 크기가 같아야 한다.

A./B

요소간 나눗셈. A와 B는 같은 크기여야 한다..

A\B

행렬의 좌나눗셈 inv(A)*B와 같다.

한 쪽이 스칼라이거나 크기가 같아야 한다.

A.\B

요소간 좌나눗셈. A와 B는 같은 크기여야 한다.

이 경우에도 요소간 연산자가 따로 정의되어 있으며 dot(.)으로 시작한다. 또한 행렬의 나눗셈의 경우는 역행렬과 관계되어 있으며 A/B는 A*inv(B)와, A\B는 inv(A)*B와 동일한 연산을 수행한다. inv()함수는 정방행렬의 역행렬을 구하는 함수이다.

(D) 기타 연산자

  행렬의 복소전치행렬은 작은 따옴표(‘)를 행렬의 끝에 붙여주면 구할 수 있고 단순 전치 행렬은 점 작은 따옴표 (.’)를 붙이면 된다. 복소전치행렬은 행과 열의 위치를 바꾸고 켤레복소수로 변환된 행렬을 의미하며 단순 전치 행렬은 그냥 위치만 바꾼 행렬은 의미한다.

>> A=[1, 2*%i; 3+4*%i, 5]
 A  =
    1.          2.i  
    3. + 4.i    5.  

>> B=A'
B  =
    1.     3. - 4.i  
 - 2.i    5.        

>> C=A.'
C  =
   1.     3. + 4.i  
   2.i    5.      

 

이 결과를 잘 살펴보면 B행렬은 A행렬의 복소 전치 행렬이고 C행렬은 단순 전치 행렬이라는 것을 알 수 있다.


 정방행렬의 역행렬을 구하는 함수는 inv()이고 행렬식(determinant)을 구하는 함수는 det()이다. 직전의 A행렬에 대해서 역행렬과 행렬식을 구하는 예는 다음과 같다.


>> inv(A)
 ans  =
    0.3170732 + 0.1463415i    0.0585366 - 0.1268293i  
   - 0.0731707 - 0.3414634i    0.0634146 + 0.0292683i  

>> det(A)
   ans  =
      13. - 6.i  



Posted by 살레시오
,

 생성된 행렬의 개별 요소를 접근하려면 행렬에 괄호 안에 행과 열의 번호를 콤마(,)로 구분하여 써주면 되는데 예를 들어 A행렬의 r행 c열 요소는 다음과 같이 접근한다.


 A(r, c)

 

여기서 r과 c를 인덱스(index)라고 한다. 사용 예를 들면 다음과 같다.

>> A = [ 1 2 3; 4 5 6]
>> b = A(1, 2) // 2가 변수 b에 저장된다.
>> A(2,3) = 3*%i // 2행 3열의 요소가 6에서 3i 로 변경된다.

만약  B가 벡터라면 다음과 같이 두 가지 방법으로 인덱싱을 할 수 있다.


>> B = [2 3 5 7 11 13 17 19]
>> c = B(1, 5)  // 1행 5열 요소이므로 11이 변수 c에 저장된다.
>> d = B(5) // 위와 같다.
>> E = (1:100)’
>> f = E(5,1) // 5행 1열의 요소이므로 5가 변수 f에 저장된다.
>> g = E(5) // 위와 같다.

 

이 예제와 같이 벡터의 인덱싱은 하나만 지정할 수 있다.


 사실 행렬은 내부적으로 1차원 배열로 관리되며 따라서 인덱스를 하나만 지정할 수는 있다. 예를 들어 다음과 같이 H행렬이 있다고 가정할 때


>> H = [ 10, 20, 30; -40, -50, -60,]

 

H(1)은 H(1,1)과 같이 10이고 H(2)는 H(2,1)의 요소인 -40이다. H(3)은 H(2,1)과 같다.

H(1) == H(1,1)

H(3) == H(1,2)

H(5) == H(1,3)

H(2) == H(2,1)

H(4) == H(2,2)

H(6) == H(2,3)

[ 그림 1] H행렬의 인덱싱

하지만 행렬의 경우 이런 방식으로 인덱싱하는 것을 추천하지 않으며 사용 빈도도 낮다.

 하나의 행 또는 하나의 열 전체를 선택하고자 할 때는 콜론(:)을 인덱스로 사용한다. 예를 들어서 H행렬의 1행 전체와 2열 전체를 선택해서 J1과 J2에 대입하고자 하면 다음과 같이 한다.


>> J1=H(1,:) // 1행, 전체 (즉 그냥 1행)
J1  =
    10.    20.    30.  
>> J2=H(:,2) // 전체. 2열 (즉 그냥 2열)
J2  =
    20.  
  - 50.  

이와 같이 콜론(:)이 인덱싱에서 단독으로 쓰이면 전체(all)의 의미를 갖는다. 혼동의 여지가 있는 것은 이전 포스트에서 설명한 콜론(:)연산자의 경우이다. 예를 들어서 2x100 행렬 K를 다음과 같이 생성했다고 가정해 보자.

>> K = [1:100; 100:-1:1]

이 행렬의 1열부터 10열까지 동시에 선택해서 변수 L에대입하려면 다음과 같이 하면 된다.


>> L = K(:, 1:10)

 

두 번째 열인덱스에 1:10 이라고 콜론 연산자를 사용했다. 따라서 이 명령은 다음과 완전히 동일하다.

>> L = K(:, [1 2 3 4 5 6 7 8 0 10])


이렇게 하는 것 보다는 전자가 훨씬 간단하므로 전자를 사용할 것이다. 하지만 콜론 연산자를 사용하는 것은 연속되거나 등간격의  행이나 열을 선택하는 경우에만 사용할 수 있다. 예를 들어서 2열, 4열, 6열… 20열을 동시에 취하려면 다음과 같이 하면 된다..

>> M = K(:, 2:2:20)


하지만 등간격이 아닌 경우에는 행벡터로 각각을 직접 지정해 주어야 한다. 예를 들어서 1열, 2열, 3열 5열 7열 11열 을 동시에 취하려면 다음과 같이 하면 된다.


>> M = K(:, [1 2 3 4 5 11])

등간격이 아니므로 이렇게 직접 지정해 주어야 한다.


 만약 어떤 행렬의 가장 마지막 행(또는 열)을 선택하고 싶다면 $지정자를 이용하면 된다.(MATLAB의 경우에는 end 지정자가 있다.) 예를 들어 K행렬의 가장 마지막 열을 N변수에 대입하고 싶다면다음과  같이 하면 된다.


>>N=K(:,$)
N  =
   100.  
   1.  

 

다른 예로 P라는 100x100는 행렬이 있다고 하고 이 행렬의 마지막 행의 1열부터 50열까지를 선택하고 싶다면

>> P($, 1:50)

라고 지정하면 된다. 마지막행 전체를 선택하려면 P($ , :)라고 하면 될 것이다.

 한 가지 특이한 점은 이 $ 지정자는 특정한 값을 가지지 않는데도 불구하고  마치 특수 상수처럼 사용된다는 점이다. 이 말은 이 지정자가 자유롭게 변수에 저장될 수 있다는 말이며 다음과 같은 명령이 가능하다.


>> x = $
>> y = [ 3 5 7 $]
>> z = 5:$
>> Q = P(:, z)

이 예의 마지막 명령은 P행렬의 5열부터 마지막 열까지를 취해서 Q변수에 대입하는 것이다.




Posted by 살레시오
,

 Scilab의 기본 데이타형은 행렬(matrix)이며 스칼라도 내부적으로는 1x1행렬로 취급된다. 벡터도 마찬가지로 nx1 행렬 (열벡터) 혹은 1xn 행렬 (행벡터) 로 취급된다. 행렬의 요소는 숫자, 불리언, 문자열, 다항식 등 일반적인 Scilab 객체가 될 수 있다. 일 반적으로 그냥 벡터라 하면 열벡터(column vector)를 의미하는 경우가 많으므로 앞으로 그냥 벡터라고 하면 열벡터를 지칭하며 행벡터는 명시적으로 표기하도록 하겠다.


 함수에 넘겨주는 입력 파라메터도 행렬이고 함수의 수행 결과 생성되는 출력값도 역시 행렬이다. 편의상  다음과 같이 구분한다.

❶ 스칼라 : 1x1 차원의 행렬

❷ 벡터 : nx1 차원의 행렬 (행벡터는 1xn 행렬), n ≥ 1 인 정수(스칼라 포함)

❸ 행렬 : mxn 차원의 행렬, m,n ≥ 1 인 정수 (스칼라, 벡터포험)

 행렬을 입력할 때는 대괄호 [ ] 를 사용하며 콤마(,)나 공백을 이용하여 요소 간을 구별한다. 세미콜론(;) 혹은 다음 줄이 행들을 구분한다. (이것은 Matlab 이나 Octave와 동일하다.) 따라서 다음 네 가지가 완전히 동일한 2x3 행렬을 생성한다.

>> A = [1, 2, 3; 4, 5, 6]
>> A = [1 2 3; 4 5 6]
>> A = [1,2,3
4,5,6]
>> A = [1 2 3
4 5 6]

행이 두 개 이상일 때는 반드시 행들의 요소 갯수가 같아야 함에 유의해야 한다. 예를 들어서 다음과 같은 입력은 에러를 발생시킬 것이다. 왜냐하면 1행의 크기는 3인데 2행의 크기는 2이기 때문이다.


>> B = [ 1 2 3; 4 5]

행렬의 요소는 복소수도 가능하고 문자열도 가능하다. 예를 들어 다음과 같다.

복소행렬을 생성할 때 주의할 점은 실수부와 허수부사이에 공백문자가 있으면 안된다는 것이다. 다음의 C행렬과 D행렬은 크기가 다른 행렬이 되버린다.(왜?)


>> C = [2+3*%i, 4]
>> D = [2 +3*%i, 4]

 

문자열을 요소로 하는 행렬도 가능하다. 예를 들면 다음과 같다.

>> E = [“abc” “def”]
>> F = [“hello”, “world”; “My name is”, ‘Salecio’]    

그러나 한 행렬의 요소들이 숫자나 문자열이 섞일 수는 없다. 또한 정수형과 실수형은 데이터형이 다르기 때문에 한 행렬에 섞일 수도 없다. 따라서 다음과 같은 입력은 에러를 발생시킨다.


>> G = [ 1 2; ‘abc’, 4]
>> K = [int8(1) 2; 3 4]

 

첫 번째 G는 숫자와 문자열을 한 행렬에 섞어서 입력했기 때문에 에러를 발생하며 두 번째 K는 정수형과 실수형이 섞여있기 때문에 에러를 발생한다.

 반면에 진리값을 나타내는 %T(혹은 %t) 와 %F( 혹은 %f)는 특수한 상수이지만 내부적으로 (더블형) 실수 1과 0으로 취급된다. 따라서 이들 값을 숫자형과 섞어서 사용할 수 있다.

이미 생성된 행렬을 이용하여 새로운 행렬을 생성할 수도 있다.

>> A = [ 1 2; 3 4]
>> B = [ A; 5 6]
>> C = [ A [5 6; 7 8] ]
>> D = [A A]
>> E = [A; A]

두 행렬을 옆으로 연결할 때에는 행의 수가 같아야하고 위아래로 연결할 때는 열의 수가 같아야 에러가 발생하지 않는다.

콜론(:) 연산자

 행벡터 혹은 열벡터를 입력하거나, 생성시켜야 하는 경우에 각 벡터 요소들의 증가분이나  감소분이 일정한 경우가 있다. 이 경우에는 콜론(:) 연산자를 이용하면 된다. 이 연산자는 사용 빈도가 높으므로 잘 숙지해 두어야 한다. 입력형식은 아래와 같다.


>> 변수 = 초기값:증감값:최종


이 명령은 초기값으로부터 최종값까지 증감값만큼 증감시킨 수열을 요소로 갖는 행벡터를 생성하여 변수에 저장하게 된다. (행벡터를 생성한다는데 주의하자!) 예를 들어, 변수 a에 0부터 100까지 10의 간격으로 행벡터를 만들고자 한다면 다음과 같이 입력하여 실행한다.



만약 증가분이 1이라면 이것은 생략할 수 있다. 만약 0부터 20까지 1씩 증가시킨 값들을 요소로 갖는 행벡터를 만들고 싶다면 다음과 같이 한다.


>> b=1:20

 

10부터 1씩 감소시켜서 0까지의 값을 요소로 갖는 행벡터는 다음과 같이 생성할 수 있다.

>> c = 10:-1:0

콜론 연산자는 사용 빈도가 굉장히 높으므로 잘 숙지하고 있어야 한다.



Posted by 살레시오
,

 허수는 Scilab에서 %i 로 입력하므로 복소수도 이것을 이용하여 입력할 수 있다. 예를 들어서 복소수 3i, 2-4i 는 다음과 같이 입력한다.

>> a=3*%i
>> b=2-4*%i

허수부와 허수사이에 곱셈(*) 기호를 빠트리지 않도록 주의하자. 또한 실수부와 허수부의 데이터형은 같아야 에러를 발생시키지 않는다.


 복소수를 생성하는 다른 방법으로 complex()함수를 사용하는 방법이 있다. 위의 예와 동일한 입력은 다음과 같다.


>> a=complex(0, 3)
>> b=complex(2, -4)

 

함수 complex(a, b) 에서 a는 실수부 b는 허수부인데 일반적으로 행렬이 될 수 있다. 둘 중 하나라도 스칼라일 경우 나머지가 행렬일 경우는 에러를 발생시키지 않는다.

그러나 만약 a와 b 둘 다 스칼라가 아니라면 서로 차수가 같아야 에러를 발생시키지 않는다.

위 그림의 예에서는 두 행렬의 차수가 같지 않아서 에러를 발생시킨 것이다.

 복소수 관련 함수는 다음 표와 같다.


[표 1] 복소수 관련 함수들

real(z)

복소수 z의 실수부 반환

imag(z)

복소수 z의 허수부 반환

imult(z)

z*%i 결과 반환

isreal(z)

z가 복소수라면 %F 반환

abs(z)

z의 크기를 반환

z’

z의 켤레복소수를 구한다. 만약 Z가 행렬이라면 복소전치행렬을 구한다.

다음 그림에 사용 예를 들었다.

한 가지 유의할 것은 isreal()함수의 결과는 행렬의 모든 요소가 실수일 경우에만 %T 이고 하나라도 복소수가 있다면 %F라는 것이다. 즉, 각각의 요소에 대해서 논리연산을 한 결과를 반환하지 않는다.



Posted by 살레시오
,

실수형 데이터

기본적으로 Scilab에서 숫자는 배정도 (C 언어의 double형, 8바이트) 실수형이며 단정도 (C 언어의 float형) 실수는 사용되지 않는다. Scilab뿐만 아니라 다른 수치해석 프로그램에서도 계산 결과의 정밀도가 중요하기 때문에 보통 실수는 정확도가 가장 높은  배정도 실수형으로 다룬다. 따라서 다음과 같이 입력하면 변수 x에 저장되는 수는 보기에는 정수이지만 내부적으로는 double형 실수이며 8바이트가 할당된다.

>> x = 1

이러한 배정도 실수형의 유효 자리는 보통 16자리인데 실용적인 공학 문제를 다룰 때는 대부분의 경우 크게 문제가 되지 않는다. 또한 배정도 실수형으로 다룰 수 있는 정수의 범위는 ~ 이며 이 범위 안에서의 정수 연산은 항상 정확한 값을 가진다. 그러나 이 범위 밖의 정수 연산은 오차가 발생하게 된다.

 보통은 Scilab을 작성할 때는 주로 실수형 데이터를 사용하고 정수형은 사용 빈도가 실수형에 비해서 낮지만 정수형 데이터에 대해서도 설명하도록 하겠다.

정수형 데이터

 배정도 실수 외에 정수형으로 데이터를 변환할 수 있으며 정수형을 다시 double형으로 바꿀 수도 있는데 관련된 함수는 다음과 같다.


[표 1]  숫자형의 변환에 관련된 함수들

함수

기능

double(M)

정수형 행렬 M을 배정도 실수형으로 변환

int8(A)

행렬 A를 8비트 부호 있는 정수형으로 변환

int16(A)

행렬 A를 16비트 부호 있는 정수형으로 변환

int32(A)

행렬 A를 32비트 부호 있는 정수형으로 변환

uint8(A)

행렬 A를 8비트 부호 없는 정수형으로 변환

uint16(A)

행렬 A를 16비트 부호 없는 정수형으로 변환

uint32(A)

행렬 A를 32비트 부호 없는 정수형으로 변환

iconvert(M, itype)

행렬 M을 특정한 형식으로 변환한다.

itype = 0 : 배정도 실수형

itype = 1 : int8 형, itype = 11 : uint8 형

itype = 2 : int16 형, itype = 12 : uint16 형

itype = 4 : int32 형, itype = 14 : uint32 형

inttype(M)

행렬 M의 데이터형을 반환한다. 반환값은 다음과 같다.

0 : 배정도 실수형, 1 : int8 형, 11 : uint8 형, 2: int16 형, 12 : uint16 형, 4 : int32 형, 14 : uint32 형


각 정수형의 숫자 범위는 다음과 같다.

  • 부호가 있는 n비트 정수의 범위: ~

  • 부호가 없는 n비트 정수의 범위: 0 ~


따라서 만약 정수형을 사용한다면 이 범위를 고려해서 프로그래밍을 해야 한다. 연산 결과가 이 범위를 넘어갈 경우 의도하지 않은 결과가 발생함을 다음 예에서 보이고 있다.



 만약 두 정수를 더하는데 서로 자료형이 다르다면 그 결과값은 큰 쪽의 데이터형으로 맞춰진다. 즉, 8비트 정수형과 16비트 정수형을 더하면 그 결과는 16비트 정수형이 된다. 다음 예는 그 사실을 보여주고 있다. 하지만 정수형과 실수형을 연산하면 그 결과는 정수형이 되는 것에도 유의해야 한다.


 Scilab의 정수형은 순환값을 가진다.(circular integers) 이것은 정수가 상한을 넘게되면 하한값을 가지게 되고 반대로 하한값보다 더 작아지면 상한값을 가지게 된다는 의미이다. 예를 들어 int8 형의 상한값은 127이며 여기에 1을 더하면 128이 되지 못하고 하한인 -128값을 가지게 된다. 다른 예로 uint16 의 하한 값은 부호 없는 정수이므로 0인데 여기서 1을 빼게 되면 상한인 65535 가 된다는 것이다.



이에 반해서 Matlab이나 Octave에서의 정수형은 허용범위를 넘어서면 순환하는 것이 아니라 거기에서 멈춘 값을 가진다. 즉 int8(127)+1 은 상한인 127이 되며 uint16(0)-1은 0이 된다. 만약 Scilab 코드를 Matlab이나 Octave로 이식하는 경우 혹은 그 반대의 경우 유의해야 한다.



Posted by 살레시오
,